├── po ├── LINGUAS ├── meson.build ├── POTFILES ├── game-of-life.pot ├── zh_CN.po ├── en.po ├── nl.po └── pt_BR.po ├── data ├── screenshots │ ├── 1.png │ ├── 2.png │ ├── 3.png │ └── 4.png ├── com.github.sixpounder.GameOfLife.desktop.in.in ├── icons │ ├── meson.build │ └── hicolor │ │ ├── symbolic │ │ └── apps │ │ │ └── com.github.sixpounder.GameOfLife-symbolic.svg │ │ └── scalable │ │ └── apps │ │ ├── com.github.sixpounder.GameOfLife.svg │ │ └── com.github.sixpounder.GameOfLife.Devel.svg ├── meson.build ├── com.github.sixpounder.GameOfLife.gschema.xml └── com.github.sixpounder.GameOfLife.appdata.xml.in.in ├── src ├── models │ ├── mod.rs │ ├── prelude.rs │ └── universe.rs ├── services │ ├── mod.rs │ ├── gio_utils.rs │ └── settings.rs ├── assets │ ├── templates │ │ ├── glider.univ │ │ ├── pulsar.univ │ │ ├── quadpole.univ │ │ ├── spaceship.univ │ │ └── circle_of_fire.univ │ └── icons │ │ ├── paintbrush-symbolic.svg │ │ ├── dice3-symbolic.svg │ │ └── snapshots-alt-symbolic.svg ├── widgets │ ├── universe_grid.ui │ ├── mod.rs │ ├── new_universe_view.ui │ ├── universe_controls.rs │ ├── new_universe_view.rs │ ├── preferences_window.ui │ ├── preferences_window.rs │ └── universe_controls.ui ├── gtk │ ├── style.css │ └── help-overlay.ui ├── i18n.rs ├── config.rs.in ├── window.ui ├── game_of_life.gresource.xml ├── main.rs ├── meson.build └── application.rs ├── .gitignore ├── meson_options.txt ├── .rustfmt.toml ├── .editorconfig ├── Cargo.toml ├── .github └── workflows │ └── issues.yaml ├── README.md ├── com.github.sixpounder.GameOfLife.json ├── meson.build ├── .reuse └── dep5 └── LICENSES └── CC0-1.0.txt /po/LINGUAS: -------------------------------------------------------------------------------- 1 | en 2 | fr 3 | it 4 | nl 5 | pt_BR 6 | zh_CN 7 | -------------------------------------------------------------------------------- /data/screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/data/screenshots/1.png -------------------------------------------------------------------------------- /data/screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/data/screenshots/2.png -------------------------------------------------------------------------------- /data/screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/data/screenshots/3.png -------------------------------------------------------------------------------- /data/screenshots/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/data/screenshots/4.png -------------------------------------------------------------------------------- /src/models/mod.rs: -------------------------------------------------------------------------------- 1 | mod prelude; 2 | mod universe; 3 | 4 | pub use prelude::*; 5 | pub use universe::*; 6 | -------------------------------------------------------------------------------- /src/services/mod.rs: -------------------------------------------------------------------------------- 1 | mod gio_utils; 2 | mod settings; 3 | 4 | pub use gio_utils::*; 5 | pub use settings::*; 6 | -------------------------------------------------------------------------------- /src/assets/templates/glider.univ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/src/assets/templates/glider.univ -------------------------------------------------------------------------------- /src/assets/templates/pulsar.univ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/src/assets/templates/pulsar.univ -------------------------------------------------------------------------------- /src/assets/templates/quadpole.univ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/src/assets/templates/quadpole.univ -------------------------------------------------------------------------------- /src/assets/templates/spaceship.univ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/src/assets/templates/spaceship.univ -------------------------------------------------------------------------------- /src/assets/templates/circle_of_fire.univ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixpounder/game-of-life/HEAD/src/assets/templates/circle_of_fire.univ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Common exclusions 2 | .flatpak-builder 3 | *.log 4 | tmp 5 | 6 | # Generated source files 7 | src/config.rs 8 | 9 | target 10 | vendor 11 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option ( 2 | 'profile', 3 | type: 'combo', 4 | choices: [ 5 | 'default', 6 | 'development' 7 | ], 8 | value: 'default', 9 | ) 10 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext(meson.project_name(), 2 | args: [ 3 | '--directory=' + meson.project_source_root(), 4 | '--keyword=i18n' 5 | ], 6 | preset: 'glib' 7 | ) 8 | -------------------------------------------------------------------------------- /src/widgets/universe_grid.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /src/widgets/mod.rs: -------------------------------------------------------------------------------- 1 | mod new_universe_view; 2 | mod preferences_window; 3 | mod universe_controls; 4 | mod universe_grid; 5 | 6 | pub use new_universe_view::*; 7 | pub use preferences_window::*; 8 | pub use universe_controls::*; 9 | pub use universe_grid::*; 10 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | condense_wildcard_suffixes = true 2 | format_code_in_doc_comments = true 3 | group_imports = "StdExternalCrate" 4 | imports_granularity = "Crate" 5 | newline_style = "Unix" 6 | normalize_comments = true 7 | normalize_doc_attributes = true 8 | wrap_comments = true 9 | -------------------------------------------------------------------------------- /src/gtk/style.css: -------------------------------------------------------------------------------- 1 | 2 | button.large { 3 | min-width: 48px; 4 | min-height: 48px; 5 | } 6 | 7 | button.small { 8 | min-width: 24px; 9 | min-height: 24px; 10 | } 11 | 12 | button.play { 13 | background-color: #26a269; 14 | } 15 | 16 | button.stop { 17 | background-color: #c64600; 18 | } 19 | -------------------------------------------------------------------------------- /src/i18n.rs: -------------------------------------------------------------------------------- 1 | use gettextrs::gettext; 2 | 3 | pub fn i18n(format: &str) -> String { 4 | gettext(format) 5 | } 6 | 7 | pub fn translators_list() -> Vec<&'static str> { 8 | vec![ 9 | "Andrea Coronese (English, Italian)", 10 | "Rene Coty (French)", 11 | "Philip Goto (dutch)", 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /data/com.github.sixpounder.GameOfLife.desktop.in.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Game of Life 3 | GenericName=Game of Life Simulator 4 | Exec=game-of-life 5 | Icon=@APPLICATION_ID@ 6 | Terminal=false 7 | Type=Application 8 | Categories=GNOME;GTK;Game; 9 | StartupNotify=true 10 | X-SingleMainWindow=true 11 | Keywords=simulation;game; 12 | -------------------------------------------------------------------------------- /po/POTFILES: -------------------------------------------------------------------------------- 1 | data/com.github.sixpounder.GameOfLife.desktop.in.in 2 | data/com.github.sixpounder.GameOfLife.appdata.xml.in.in 3 | data/com.github.sixpounder.GameOfLife.gschema.xml 4 | src/gtk/help-overlay.ui 5 | src/window.rs 6 | src/window.ui 7 | src/widgets/universe_controls.ui 8 | src/widgets/new_universe_view.ui 9 | src/widgets/preferences_window.ui 10 | -------------------------------------------------------------------------------- /src/config.rs.in: -------------------------------------------------------------------------------- 1 | pub static VERSION: &str = @VERSION@; 2 | pub static GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@; 3 | pub static LOCALEDIR: &str = @LOCALEDIR@; 4 | pub static PKGDATADIR: &str = @PKGDATADIR@; 5 | pub static APPLICATION_ID: &str = @APPLICATION_ID@; 6 | pub static APPLICATION_G_PATH: &str = @APPLICATION_G_PATH@; 7 | 8 | pub static G_LOG_DOMAIN: &str = @APPLICATION_ID@; 9 | 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 4 10 | 11 | [*.css] 12 | indent_size = 2 13 | 14 | [*.ui] 15 | indent_size = 2 16 | 17 | [*.xml] 18 | indent_size = 2 19 | 20 | [meson.build] 21 | indent_size = 2 22 | 23 | [*.md] 24 | max_line_length = 80 25 | trim_trailing_whitespace = false 26 | 27 | [*.json] 28 | indent_size = 4 29 | -------------------------------------------------------------------------------- /data/icons/meson.build: -------------------------------------------------------------------------------- 1 | application_id = 'com.github.sixpounder.GameOfLife' 2 | 3 | scalable_dir = join_paths('hicolor', 'scalable', 'apps') 4 | install_data( 5 | join_paths(scalable_dir, ('@0@.svg').format(application_id)), 6 | install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir) 7 | ) 8 | 9 | symbolic_dir = join_paths('hicolor', 'symbolic', 'apps') 10 | install_data( 11 | join_paths(symbolic_dir, ('@0@-symbolic.svg').format(application_id)), 12 | install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir) 13 | ) 14 | -------------------------------------------------------------------------------- /src/assets/icons/paintbrush-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "game-of-life" 3 | version = "0.6.1" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | async-channel = "2.5.0" 8 | gettext-rs = { version = "0.7", features = ["gettext-system"] } 9 | rand = "0.8.5" 10 | once_cell = "1.13.1" 11 | bincode = "1.3.3" 12 | serde = { version = "1.0.144", features = ["derive"] } 13 | 14 | [dependencies.adw] 15 | package = "libadwaita" 16 | version = "0.8.0" 17 | features = ["v1_8"] 18 | 19 | [dependencies.gtk] 20 | package = "gtk4" 21 | version = "0.10.2" 22 | 23 | [dependencies.glib] 24 | version = "0.21.4" 25 | features = ["log", "log_macros"] 26 | 27 | -------------------------------------------------------------------------------- /.github/workflows/issues.yaml: -------------------------------------------------------------------------------- 1 | name: Close inactive issues 2 | on: 3 | schedule: 4 | - cron: "30 1 * * *" 5 | 6 | jobs: 7 | close-issues: 8 | runs-on: ubuntu-latest 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | steps: 13 | - uses: actions/stale@v5 14 | with: 15 | days-before-issue-stale: 60 16 | days-before-issue-close: 14 17 | stale-issue-label: "stale" 18 | stale-issue-message: "This issue is stale because it has been open for 60 days with no activity." 19 | close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." 20 | days-before-pr-stale: -1 21 | days-before-pr-close: -1 22 | repo-token: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /src/assets/icons/dice3-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Game of Life 2 | 3 | ![Application icon](./data/icons/hicolor/scalable/apps/com.github.sixpounder.GameOfLife.svg) 4 | 5 | A simple Conway's game of life simulator for the Gnome desktop 6 | 7 | ## Installation 8 | 9 | The easieast way to install is from Flathub. 10 | 11 | 12 | 13 | ### Using Gnome Builder 14 | 15 | Just clone this repository and hit the play button. Builder 43 also let you one-click install 16 | the application to your device. 17 | 18 | ### Build from sources 19 | 20 | You will need the meson build system and flatpak builder, along with gtk4 and libadwaita devel libraries. 21 | 22 | ```bash 23 | git clone game-of-life 24 | cd game-of-life 25 | meson build --prefix=/usr/local 26 | ninja -C build 27 | ``` 28 | 29 | # Credits 30 | 31 | **Icon design:** Tobias Bernard 32 | -------------------------------------------------------------------------------- /src/assets/icons/snapshots-alt-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /data/icons/hicolor/symbolic/apps/com.github.sixpounder.GameOfLife-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/services/gio_utils.rs: -------------------------------------------------------------------------------- 1 | use crate::config::G_LOG_DOMAIN; 2 | use gtk::gio; 3 | use gtk::gio::prelude::DataInputStreamExt; 4 | 5 | const TEMPLATE_PREFIX: &str = "/com/github/sixpounder/GameOfLife/templates/"; 6 | 7 | pub struct Template {} 8 | 9 | impl Template { 10 | pub fn read_template(name: &str) -> Result, glib::Error> { 11 | let template_resource = format!("{}{}.univ", TEMPLATE_PREFIX, name.to_lowercase()); 12 | glib::g_debug!(G_LOG_DOMAIN, "Reading template from {}", template_resource); 13 | match gio::resources_open_stream(template_resource.as_str(), gio::ResourceLookupFlags::NONE) 14 | { 15 | Ok(input_stream) => { 16 | let mut buffer = vec![]; 17 | let data_stream = gio::DataInputStream::new(&input_stream); 18 | let mut bytes_read: usize = 0; 19 | while let Ok(byte) = data_stream.read_byte(gio::Cancellable::NONE) { 20 | buffer.push(byte); 21 | bytes_read += 1; 22 | } 23 | 24 | glib::g_debug!(G_LOG_DOMAIN, "Read {} bytes from template", bytes_read); 25 | Ok(buffer) 26 | } 27 | Err(err) => Err(err), 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /com.github.sixpounder.GameOfLife.json: -------------------------------------------------------------------------------- 1 | { 2 | "app-id" : "com.github.sixpounder.GameOfLife", 3 | "runtime" : "org.gnome.Platform", 4 | "runtime-version" : "49", 5 | "sdk" : "org.gnome.Sdk", 6 | "sdk-extensions" : [ 7 | "org.freedesktop.Sdk.Extension.rust-stable" 8 | ], 9 | "command" : "game-of-life", 10 | "finish-args" : [ 11 | "--share=ipc", 12 | "--socket=fallback-x11", 13 | "--device=dri", 14 | "--socket=wayland" 15 | ], 16 | "build-options" : { 17 | "append-path" : "/usr/lib/sdk/rust-stable/bin", 18 | "build-args" : [ 19 | "--share=network" 20 | ], 21 | "env" : { 22 | "G_MESSAGES_DEBUG" : "none", 23 | "RUST_BACKTRACE" : "1", 24 | "RUST_LOG" : "game-of-life=debug,glib=debug" 25 | } 26 | }, 27 | "cleanup" : [ 28 | "/include", 29 | "/lib/pkgconfig", 30 | "/man", 31 | "/share/doc", 32 | "/share/gtk-doc", 33 | "/share/man", 34 | "/share/pkgconfig", 35 | "*.la", 36 | "*.a" 37 | ], 38 | "modules" : [ 39 | { 40 | "name" : "game-of-life", 41 | "builddir" : true, 42 | "buildsystem" : "meson", 43 | "sources" : [ 44 | { 45 | "type" : "git", 46 | "url" : "https://github.com/sixpounder/game-of-life" 47 | } 48 | ] 49 | } 50 | ] 51 | } 52 | 53 | -------------------------------------------------------------------------------- /src/window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/game_of_life.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gtk/style.css 5 | window.ui 6 | gtk/help-overlay.ui 7 | widgets/universe_grid.ui 8 | widgets/universe_controls.ui 9 | widgets/new_universe_view.ui 10 | widgets/preferences_window.ui 11 | 12 | 13 | assets/icons/paintbrush-symbolic.svg 14 | assets/icons/dice3-symbolic.svg 15 | assets/icons/snapshots-alt-symbolic.svg 16 | 17 | 18 | assets/templates/glider.univ 19 | assets/templates/pulsar.univ 20 | assets/templates/spaceship.univ 21 | assets/templates/quadpole.univ 22 | assets/templates/circle_of_fire.univ 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod application; 2 | mod config; 3 | mod i18n; 4 | mod models; 5 | mod services; 6 | mod widgets; 7 | mod window; 8 | 9 | use self::application::GameOfLifeApplication; 10 | use self::window::GameOfLifeWindow; 11 | 12 | use config::{GETTEXT_PACKAGE, LOCALEDIR, PKGDATADIR}; 13 | use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain}; 14 | use gtk::gio; 15 | use gtk::prelude::*; 16 | 17 | fn main() { 18 | // Set up gettext translations 19 | bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain"); 20 | bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8") 21 | .expect("Unable to set the text domain encoding"); 22 | textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain"); 23 | 24 | // Load resources 25 | let resources = gio::Resource::load(PKGDATADIR.to_owned() + "/game-of-life.gresource") 26 | .expect("Could not load resources"); 27 | gio::resources_register(&resources); 28 | 29 | gtk::glib::set_application_name("Game of Life"); 30 | gtk::glib::set_program_name(Some("game-of-life")); 31 | 32 | // Create a new GtkApplication. The application manages our main loop, 33 | // application windows, integration with the window manager/compositor, and 34 | // desktop features such as file opening and single-instance applications. 35 | let app = GameOfLifeApplication::new( 36 | "com.github.sixpounder.GameOfLife", 37 | &gio::ApplicationFlags::empty(), 38 | ); 39 | 40 | // Run the application. This function will block until the application 41 | // exits. Upon return, we have our exit code to return to the shell. (This 42 | // is the code you see when you do `echo $?` after running a command in a 43 | // terminal. 44 | std::process::exit(app.run().into()); 45 | } 46 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('game-of-life', 'rust', 2 | version: '0.6.1', 3 | license: ['GPL-3.0'], 4 | meson_version: '>= 0.59.0', 5 | default_options: [ 'warning_level=2', 6 | 'werror=false', 7 | ], 8 | ) 9 | 10 | dependency('gtk4', version: '>= 4.6.0') 11 | dependency('libadwaita-1') 12 | 13 | i18n = import('i18n') 14 | gnome = import('gnome') 15 | fs = import('fs') 16 | 17 | add_global_arguments('-DGETTEXT_PACKAGE="@0@"'.format (meson.project_name()), language:'c') 18 | 19 | cargo = find_program('cargo', required: true) 20 | 21 | cargo_sources = files( 22 | 'Cargo.toml', 23 | 'Cargo.lock', 24 | ) 25 | 26 | if get_option('profile') == 'development' 27 | profile = '.Devel' 28 | if fs.is_dir('.git') 29 | vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD').stdout().strip() 30 | if vcs_tag == '' 31 | version_suffix = '-devel' 32 | else 33 | version_suffix = '-@0@'.format(vcs_tag) 34 | endif 35 | else 36 | version_suffix = '-devel' 37 | endif 38 | else 39 | profile = '' 40 | version_suffix = '' 41 | endif 42 | 43 | application_id = 'com.github.sixpounder.GameOfLife@0@'.format(profile) 44 | 45 | subdir('data') 46 | subdir('src') 47 | subdir('po') 48 | 49 | meson.add_dist_script( 50 | 'build-aux/dist-vendor.sh', 51 | meson.project_source_root(), 52 | meson.project_build_root() / 'meson-dist' / '@0@-@1@'.format(meson.project_name(), meson.project_version()), 53 | ) 54 | 55 | gnome.post_install( 56 | glib_compile_schemas: true, 57 | gtk_update_icon_cache: true, 58 | update_desktop_database: true, 59 | ) 60 | 61 | summary({ 62 | 'prefix': get_option('prefix'), 63 | 'libdir': get_option('libdir'), 64 | 'datadir': get_option('datadir'), 65 | 'bindir': get_option('bindir'), 66 | }, 67 | section: 'Directories', 68 | ) 69 | 70 | summary({ 71 | 'Profile': get_option('profile'), 72 | }, 73 | section: 'Build options', 74 | ) 75 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | desktop_data = configuration_data() 2 | desktop_data.set('APPLICATION_ID', application_id) 3 | desktop_file = i18n.merge_file( 4 | input: configure_file( 5 | input: 'com.github.sixpounder.GameOfLife.desktop.in.in', 6 | output: 'com.github.sixpounder.GameOfLife.desktop.in', 7 | configuration: desktop_data, 8 | ), 9 | output: 'com.github.sixpounder.GameOfLife.desktop', 10 | type: 'desktop', 11 | po_dir: '../po', 12 | install: true, 13 | install_dir: join_paths(get_option('datadir'), 'applications') 14 | ) 15 | 16 | desktop_utils = find_program('desktop-file-validate', required: false) 17 | if desktop_utils.found() 18 | test('Validate desktop file', desktop_utils, 19 | args: [desktop_file] 20 | ) 21 | endif 22 | 23 | appstream_data = configuration_data() 24 | appstream_data.set('APPLICATION_ID', application_id) 25 | appstream_file = i18n.merge_file( 26 | input: configure_file( 27 | input: 'com.github.sixpounder.GameOfLife.appdata.xml.in.in', 28 | output: 'com.github.sixpounder.GameOfLife.appdata.xml.in', 29 | configuration: appstream_data, 30 | ), 31 | output: 'com.github.sixpounder.GameOfLife.appdata.xml', 32 | po_dir: '../po', 33 | install: true, 34 | install_dir: join_paths(get_option('datadir'), 'appdata') 35 | ) 36 | 37 | appstream_util = find_program('appstream-util', required: false) 38 | if appstream_util.found() 39 | test('Validate appstream file', appstream_util, 40 | args: ['validate', appstream_file] 41 | ) 42 | endif 43 | 44 | install_data('com.github.sixpounder.GameOfLife.gschema.xml', 45 | install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas') 46 | ) 47 | 48 | gnome.compile_schemas() 49 | 50 | compile_schemas = find_program('glib-compile-schemas', required: true) 51 | if compile_schemas.found() 52 | test('Validate and compile schema file', 53 | compile_schemas, 54 | args: ['--strict', '--dry-run', meson.current_source_dir()], 55 | suite: ['lint'] 56 | ) 57 | endif 58 | 59 | subdir('icons') 60 | -------------------------------------------------------------------------------- /data/com.github.sixpounder.GameOfLife.gschema.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | "#64BAFF" 6 | 7 | 8 | "#FAFAFA" 9 | 10 | 11 | "#C061CB" 12 | 13 | 14 | "#3D3846" 15 | 16 | 17 | false 18 | Fades out cells when they die instead of deleting them in one go 19 | 20 | 21 | 10 22 | The number of generations per seconds that should be computed when a simulation is running 23 | 24 | 25 | 600 26 | 27 | 28 | 600 29 | 30 | 31 | 200 32 | The width of the universe being generated, in cells number 33 | 34 | 35 | 200 36 | The height of the universe being generated, in cells number 37 | 38 | 39 | true 40 | Wheter to draw cells outline in universe grid 41 | 42 | 43 | true 44 | Wheter to allow universe rendering when the application window is resizing 45 | 46 | 47 | true 48 | Wheter to show an interaction hint on design mode activated 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name()) 2 | 3 | gnome.compile_resources('game-of-life', 4 | 'game_of_life.gresource.xml', 5 | gresource_bundle: true, 6 | install: true, 7 | install_dir: pkgdatadir, 8 | ) 9 | 10 | g_path_template = '/@0@' 11 | g_path = g_path_template.format(application_id.replace('.', '/')) 12 | 13 | conf = configuration_data() 14 | conf.set_quoted('VERSION', meson.project_version()) 15 | conf.set_quoted('GETTEXT_PACKAGE', 'game-of-life') 16 | conf.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir'))) 17 | conf.set_quoted('PKGDATADIR', pkgdatadir) 18 | conf.set_quoted('APPLICATION_ID', application_id) 19 | conf.set_quoted('APPLICATION_G_PATH', g_path) 20 | 21 | configure_file( 22 | input: 'config.rs.in', 23 | output: 'config.rs', 24 | configuration: conf 25 | ) 26 | 27 | # Copy the config.rs output to the source directory. 28 | run_command( 29 | 'cp', 30 | join_paths(meson.project_build_root(), 'src', 'config.rs'), 31 | join_paths(meson.project_source_root(), 'src', 'config.rs'), 32 | check: true 33 | ) 34 | 35 | rust_sources = files( 36 | 'application.rs', 37 | 'config.rs', 38 | 'main.rs', 39 | 'window.rs', 40 | 'i18n.rs', 41 | 'widgets/mod.rs', 42 | 'widgets/universe_grid.rs', 43 | 'widgets/universe_controls.rs', 44 | 'widgets/new_universe_view.rs', 45 | 'widgets/preferences_window.rs', 46 | 'models/mod.rs', 47 | 'models/prelude.rs', 48 | 'models/universe.rs', 49 | 'services/mod.rs', 50 | 'services/settings.rs' 51 | ) 52 | 53 | sources = [cargo_sources, rust_sources] 54 | 55 | cargo_script = find_program(join_paths(meson.project_source_root(), 'build-aux/cargo.sh')) 56 | cargo_release = custom_target( 57 | 'cargo-build', 58 | build_by_default: true, 59 | input: sources, 60 | output: meson.project_name(), 61 | console: true, 62 | install: true, 63 | install_dir: get_option('bindir'), 64 | command: [ 65 | cargo_script, 66 | meson.project_build_root(), 67 | meson.project_source_root(), 68 | '@OUTPUT@', 69 | get_option('buildtype'), 70 | meson.project_name(), 71 | ] 72 | ) 73 | 74 | # test( 75 | # 'Lint code with clippy', 76 | # cargo, 77 | # args: [ 78 | # 'clippy', 79 | # '--no-deps', 80 | # '--manifest-path', 81 | # join_paths(meson.project_source_root(), 'Cargo.toml') 82 | # ] 83 | # ) 84 | -------------------------------------------------------------------------------- /src/models/prelude.rs: -------------------------------------------------------------------------------- 1 | use gtk::glib; 2 | use serde::{Deserialize, Serialize}; 3 | use std::fmt; 4 | 5 | #[derive(Clone, Debug, glib::Enum, Copy, PartialEq)] 6 | #[enum_type(name = "UniverseGridMode")] 7 | pub enum UniverseGridMode { 8 | /// The grid can receive interactive inputs, such as mouse clicks 9 | Unlocked = 0, 10 | 11 | /// The grid will not receive interactive inputs 12 | Locked = 1, 13 | } 14 | 15 | impl Default for UniverseGridMode { 16 | fn default() -> Self { 17 | Self::Locked 18 | } 19 | } 20 | 21 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] 22 | pub enum UniverseCell { 23 | Dead = 0, 24 | Alive = 1, 25 | } 26 | 27 | impl UniverseCell { 28 | pub fn is_alive(&self) -> bool { 29 | matches!(self, UniverseCell::Alive) 30 | } 31 | } 32 | 33 | impl std::ops::Not for UniverseCell { 34 | type Output = UniverseCell; 35 | fn not(self) -> Self::Output { 36 | match self { 37 | UniverseCell::Alive => UniverseCell::Dead, 38 | UniverseCell::Dead => UniverseCell::Alive, 39 | } 40 | } 41 | } 42 | 43 | impl fmt::Display for UniverseCell { 44 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 45 | write!( 46 | f, 47 | "{}", 48 | match self.is_alive() { 49 | true => "Alive", 50 | _ => "Dead", 51 | } 52 | ) 53 | } 54 | } 55 | 56 | #[derive(Debug, Clone, Copy)] 57 | pub struct UniversePoint { 58 | row: usize, 59 | column: usize, 60 | cell: UniverseCell, 61 | corpse_heat: f64, 62 | } 63 | 64 | impl UniversePoint { 65 | pub fn new(row: usize, column: usize, cell: UniverseCell, corpse_heat: f64) -> Self { 66 | Self { 67 | row, 68 | column, 69 | cell, 70 | corpse_heat, 71 | } 72 | } 73 | 74 | pub fn row(&self) -> usize { 75 | self.row 76 | } 77 | 78 | pub fn column(&self) -> usize { 79 | self.column 80 | } 81 | 82 | pub fn cell(&self) -> &UniverseCell { 83 | &self.cell 84 | } 85 | 86 | pub fn set_cell(&mut self, value: UniverseCell) { 87 | self.cell = value; 88 | } 89 | 90 | pub fn corpse_heat(&self) -> f64 { 91 | self.corpse_heat 92 | } 93 | } 94 | 95 | pub trait UniversePointMatrix { 96 | type SetCellError; 97 | 98 | /// Gets the number of columns for this universe 99 | fn columns(&self) -> usize; 100 | 101 | /// Gets the number of rows for this universe 102 | fn rows(&self) -> usize; 103 | 104 | /// Gets a point at `row` and `column` 105 | fn get(&self, row: usize, column: usize) -> Option; 106 | 107 | /// Sets the cell state at `row` and `column` and, if successfull, 108 | /// returns the the altered point 109 | fn set( 110 | &mut self, 111 | row: usize, 112 | column: usize, 113 | value: UniverseCell, 114 | ) -> Result; 115 | } 116 | -------------------------------------------------------------------------------- /src/gtk/help-overlay.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | True 5 | 6 | 7 | shortcuts 8 | 10 9 | 10 | 11 | General 12 | 13 | 14 | New Universe 15 | win.new 16 | 17 | 18 | 19 | 20 | Open Snapshot 21 | win.open-snapshot 22 | 23 | 24 | 25 | 26 | Save Snapshot 27 | win.snapshot 28 | 29 | 30 | 31 | 32 | Preferences 33 | app.preferences 34 | 35 | 36 | 37 | 38 | Show Shortcuts 39 | win.show-help-overlay 40 | 41 | 42 | 43 | 44 | Close 45 | app.quit 46 | 47 | 48 | 49 | 50 | 51 | 52 | Universe Control 53 | 54 | 55 | Toggle Design Mode 56 | win.toggle-design-mode 57 | 58 | 59 | 60 | 61 | Toggle Run Universe 62 | win.play 63 | 64 | 65 | 66 | 67 | Seed Universe 68 | win.random-seed 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: game-of-life 3 | Upstream-Contact: Andrea Coronese 4 | Source: https://github.com/sixpounder/game-of-life 5 | 6 | Files: .gitignore 7 | Copyright: 2022 Andrea Coronese 8 | License: CC0-1.0 9 | 10 | Files: .editorconfig 11 | Copyright: 2022 Andrea Coronese 12 | License: CC0-1.0 13 | 14 | Files: .rustfmt.toml 15 | Copyright: 2022 Andrea Coronese 16 | License: CC0-1.0 17 | 18 | Files: .github/**/* 19 | Copyright: 2023 Andrea Coronese 20 | License: CC0-1.0 21 | 22 | Files: meson_options.txt 23 | Copyright: 2023 Andrea Coronese 24 | License: GPL-3.0-or-later 25 | 26 | Files: *.build 27 | Copyright: 2023 Andrea Coronese 28 | License: GPL-3.0-or-later 29 | 30 | Files: Cargo.toml 31 | Copyright: 2022 Andrea Coronese 32 | License: GPL-3.0-or-later 33 | 34 | Files: Cargo.lock 35 | Copyright: 2022 Andrea Coronese 36 | License: GPL-3.0-or-later 37 | 38 | Files: README.md 39 | Copyright: 2022 Andrea Coronese 40 | License: CC0-1.0 41 | 42 | Files: com.github.sixpounder.GameOfLife.json 43 | Copyright: 2022 Andrea Coronese 44 | License: CC0-1.0 45 | 46 | Files: build-aux/* 47 | Copyright: 2022 Andrea Coronese 48 | License: CC0-1.0 49 | 50 | Files: po/* 51 | Copyright: 2022 Andrea Coronese 52 | License: CC0-1.0 53 | 54 | Files: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in 55 | Copyright: 2022 Andrea Coronese 56 | License: CC0-1.0 57 | 58 | Files: data/**/com.github.sixpounder.GameOfLife*.svg 59 | Copyright: 2022 Tobias Bernard 60 | License: GPL-3.0-or-later 61 | 62 | Files: data/com.github.sixpounder.GameOfLife.desktop.in.in 63 | Copyright: 2022 Andrea Coronese 64 | License: CC0-1.0 65 | 66 | Files: data/com.github.sixpounder.GameOfLife.gschema.xml 67 | Copyright: 2022 Andrea Coronese 68 | License: CC0-1.0 69 | 70 | Files: data/com.github.sixpounder.GameOfLife.service.in 71 | Copyright: 2022 Andrea Coronese 72 | License: CC0-1.0 73 | 74 | Files: data/screenshots/*.png 75 | Copyright: 2022 Andrea Coronese 76 | License: CC0-1.0 77 | 78 | Files: data/icons/hicolor/scalable/apps/com.github.sixpounder.GameOfLife.* 79 | Copyright: 2022 Andrea Coronese 80 | License: GPL-3.0-or-later 81 | 82 | Files: data/icons/hicolor/symbolic/apps/com.github.sixpounder.GameOfLife.* 83 | Copyright: 2022 Andrea Coronese 84 | License: GPL-3.0-or-later 85 | 86 | Files: *.svg 87 | Copyright: 2022 Andrea Coronese 88 | License: GPL-3.0-or-later 89 | 90 | Files: po/POTFILES.in po/LINGUAS 91 | Copyright: 2022 Andrea Coronese 92 | License: CC0-1.0 93 | 94 | Files: po/*.po 95 | Copyright: 2022 Translation authors 96 | License: GPL-3.0-or-later 97 | 98 | Files: src/game_of_life.gresource.xml 99 | Copyright: 2022 Andrea Coronese 100 | License: GPL-3.0-or-later 101 | 102 | Files: src/gtk/*.ui 103 | Copyright: 2022 Andrea Coronese 104 | License: GPL-3.0-or-later 105 | 106 | Files: src/gtk/style.css 107 | Copyright: 2022 Andrea Coronese 108 | License: GPL-3.0-or-later 109 | 110 | Files: src/**/*.ui 111 | Copyright: 2023 Andrea Coronese 112 | License: GPL-3.0-or-later 113 | 114 | Files: src/*.ui 115 | Copyright: 2023 Andrea Coronese 116 | License: GPL-3.0-or-later 117 | 118 | 119 | Files: src/*.rs 120 | Copyright: 2023 Andrea Coronese 121 | License: GPL-3.0-or-later 122 | 123 | Files: src/*.rs.in 124 | Copyright: 2023 Andrea Coronese 125 | License: GPL-3.0-or-later 126 | 127 | 128 | Files: src/**/*.rs 129 | Copyright: 2023 Andrea Coronese 130 | License: GPL-3.0-or-later 131 | 132 | Files: src/styles/*.css 133 | Copyright: 2023 Andrea Coronese 134 | License: GPL-3.0-or-later 135 | 136 | Files: **/*.build 137 | Copyright: 2023 Andrea Coronese 138 | License: GPL-3.0-or-later 139 | 140 | Files: src/assets/**/* 141 | Copyright: 2023 Andrea Coronese 142 | License: GPL-3.0-or-later 143 | 144 | -------------------------------------------------------------------------------- /data/icons/hicolor/scalable/apps/com.github.sixpounder.GameOfLife.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/widgets/new_universe_view.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/services/settings.rs: -------------------------------------------------------------------------------- 1 | use crate::config::{APPLICATION_ID, G_LOG_DOMAIN}; 2 | use glib::prelude::*; 3 | use gtk::gdk; 4 | use gtk::gio::prelude::{SettingsExt, SettingsExtManual}; 5 | 6 | #[derive(Debug, Clone)] 7 | pub struct GameOfLifeSettings { 8 | inner: gtk::gio::Settings, 9 | } 10 | 11 | impl Default for GameOfLifeSettings { 12 | fn default() -> Self { 13 | Self { 14 | inner: gtk::gio::Settings::new(APPLICATION_ID), 15 | } 16 | } 17 | } 18 | 19 | impl GameOfLifeSettings { 20 | #[allow(dead_code)] 21 | pub fn set_evolution_speed(&self, value: u32) { 22 | self.inner 23 | .set_uint("evolution-speed", value) 24 | .expect("Could not set evolution speed"); 25 | } 26 | 27 | pub fn evolution_speed(&self) -> u32 { 28 | self.inner.uint("evolution-speed") 29 | } 30 | 31 | pub fn window_width(&self) -> i32 { 32 | self.inner.int("window-width") 33 | } 34 | 35 | pub fn set_window_width(&self, value: i32) { 36 | self.inner 37 | .set_int("window-width", value) 38 | .expect("Could not store window width"); 39 | } 40 | 41 | pub fn window_height(&self) -> i32 { 42 | self.inner.int("window-height") 43 | } 44 | 45 | pub fn set_window_height(&self, value: i32) { 46 | self.inner 47 | .set_int("window-height", value) 48 | .expect("Could not store window width"); 49 | } 50 | 51 | pub fn fg_color(&self) -> String { 52 | self.inner.string("fg-color").to_string() 53 | } 54 | 55 | #[allow(dead_code)] 56 | pub fn fg_color_rgba(&self) -> gdk::RGBA { 57 | gdk::RGBA::parse(self.fg_color().as_str()).expect("Cannot parse RGBA") 58 | } 59 | 60 | #[allow(dead_code)] 61 | pub fn set_fg_color(&self, value: String) { 62 | self.inner 63 | .set_string("fg-color", value.as_str()) 64 | .expect("Could not store fg-color preference"); 65 | } 66 | 67 | pub fn bg_color(&self) -> String { 68 | self.inner.string("bg-color").to_string() 69 | } 70 | 71 | #[allow(dead_code)] 72 | pub fn set_bg_color(&self, value: String) { 73 | self.inner 74 | .set_string("bg-color", value.as_str()) 75 | .expect("Could not store bg-color preference"); 76 | } 77 | 78 | pub fn fg_color_dark(&self) -> String { 79 | self.inner.string("fg-color-dark").to_string() 80 | } 81 | 82 | #[allow(dead_code)] 83 | pub fn set_fg_color_dark(&self, value: String) { 84 | self.inner 85 | .set_string("fg-color-dark", value.as_str()) 86 | .expect("Could not store fg-color-dark preference"); 87 | } 88 | 89 | pub fn bg_color_dark(&self) -> String { 90 | self.inner.string("bg-color-dark").to_string() 91 | } 92 | 93 | #[allow(dead_code)] 94 | pub fn set_bg_color_dark(&self, value: String) { 95 | self.inner 96 | .set_string("bg-color-dark", value.as_str()) 97 | .expect("Could not store bg-color-dark preference"); 98 | } 99 | 100 | pub fn universe_width(&self) -> i32 { 101 | self.inner.int("universe-width") 102 | } 103 | 104 | pub fn set_universe_width(&self, value: i32) { 105 | self.inner 106 | .set_int("universe-width", value) 107 | .expect("Could not store default universe width"); 108 | } 109 | 110 | pub fn universe_height(&self) -> i32 { 111 | self.inner.int("universe-height") 112 | } 113 | 114 | pub fn set_universe_height(&self, value: i32) { 115 | self.inner 116 | .set_int("universe-height", value) 117 | .expect("Could not store default universe height"); 118 | } 119 | 120 | pub fn draw_cells_outline(&self) -> bool { 121 | self.inner.boolean("draw-cells-outline") 122 | } 123 | 124 | pub fn fade_out_cells(&self) -> bool { 125 | self.inner.boolean("fade-out-cells") 126 | } 127 | 128 | #[allow(dead_code)] 129 | pub fn set_draw_cells_outline(&self, value: bool) { 130 | self.inner 131 | .set_boolean("draw-cells-outline", value) 132 | .expect("Could not store cells outline preference") 133 | } 134 | 135 | pub fn show_design_hint(&self) -> bool { 136 | self.inner.boolean("show-design-hint") 137 | } 138 | 139 | pub fn set_show_design_hint(&self, value: bool) { 140 | self.inner 141 | .set_boolean("show-design-hint", value) 142 | .expect("Could not store design hint preference") 143 | } 144 | 145 | pub fn allow_render_during_resize(&self) -> bool { 146 | self.inner.boolean("allow-render-during-resize") 147 | } 148 | 149 | #[allow(dead_code)] 150 | pub fn set_allow_render_during_resize(&self, value: bool) { 151 | self.inner 152 | .set_boolean("allow-render-during-resize", value) 153 | .expect("Coult not store allow render during resize preference") 154 | } 155 | 156 | pub fn connect_changed(&self, key: &str, f: F) 157 | where 158 | F: Fn(>k::gio::Settings, &str) + 'static, 159 | { 160 | self.inner.connect_changed(Some(key), move |settings, key| { 161 | glib::info!("GSettings:{} changed", key); 162 | f(settings, key); 163 | }); 164 | } 165 | 166 | pub fn bind

(&self, key: &str, object: &P, property: &str) 167 | where 168 | P: IsA, 169 | { 170 | self.inner.bind(key, object, property).build(); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/application.rs: -------------------------------------------------------------------------------- 1 | use adw::subclass::prelude::*; 2 | use adw::prelude::*; 3 | use glib::clone; 4 | use gtk::{gio, glib}; 5 | 6 | use crate::config::{APPLICATION_ID, VERSION}; 7 | use crate::i18n::translators_list; 8 | use crate::{services::GameOfLifeSettings, widgets::GameOfLifePreferencesWindow, GameOfLifeWindow}; 9 | 10 | mod imp { 11 | use super::*; 12 | 13 | #[derive(Debug, Default)] 14 | pub struct GameOfLifeApplication {} 15 | 16 | #[glib::object_subclass] 17 | impl ObjectSubclass for GameOfLifeApplication { 18 | const NAME: &'static str = "GameOfLifeApplication"; 19 | type Type = super::GameOfLifeApplication; 20 | type ParentType = adw::Application; 21 | 22 | fn new() -> Self { 23 | Self::default() 24 | } 25 | } 26 | 27 | impl ObjectImpl for GameOfLifeApplication { 28 | fn constructed(&self) { 29 | self.parent_constructed(); 30 | let obj = self.obj(); 31 | obj.setup_gactions(); 32 | obj.set_accels_for_action("app.quit", &["q"]); 33 | obj.set_accels_for_action("app.preferences", &["comma"]); 34 | obj.set_accels_for_action("win.play", &["space"]); 35 | obj.set_accels_for_action("win.snapshot", &["s"]); 36 | obj.set_accels_for_action("win.open-snapshot", &["o"]); 37 | obj.set_accels_for_action("win.toggle-design-mode", &["e"]); 38 | obj.set_accels_for_action("win.new", &["n"]); 39 | obj.set_accels_for_action("win.new-empty", &["e"]); 40 | obj.set_accels_for_action("win.random-seed", &["r"]); 41 | } 42 | } 43 | 44 | impl ApplicationImpl for GameOfLifeApplication { 45 | // We connect to the activate callback to create a window when the application 46 | // has been launched. Additionally, this callback notifies us when the user 47 | // tries to launch a "second instance" of the application. When they try 48 | // to do that, we'll just present any existing window. 49 | fn activate(&self) { 50 | // Get the current window or create one if necessary 51 | let application = self.obj(); 52 | let window = if let Some(window) = application.active_window() { 53 | window 54 | } else { 55 | let window = GameOfLifeWindow::new(application.as_ref()); 56 | window.upcast() 57 | }; 58 | 59 | // Ask the window manager/compositor to present the window 60 | window.present(); 61 | } 62 | } 63 | 64 | impl GtkApplicationImpl for GameOfLifeApplication {} 65 | impl AdwApplicationImpl for GameOfLifeApplication {} 66 | } 67 | 68 | glib::wrapper! { 69 | pub struct GameOfLifeApplication(ObjectSubclass) 70 | @extends gio::Application, gtk::Application, adw::Application, 71 | @implements gio::ActionGroup, gio::ActionMap; 72 | } 73 | 74 | impl GameOfLifeApplication { 75 | pub fn new(application_id: &str, flags: &gio::ApplicationFlags) -> Self { 76 | // glib::Object::new::(&[("application-id", &application_id), ("flags", flags)]) 77 | glib::Object::builder() 78 | .property("application-id", application_id) 79 | .property("flags", flags) 80 | .build() 81 | } 82 | 83 | fn setup_gactions(&self) { 84 | let quit_action = gio::SimpleAction::new("quit", None); 85 | quit_action.connect_activate(clone!( 86 | #[weak(rename_to = app)] 87 | self, 88 | move |_, _| { 89 | app.quit(); 90 | } 91 | )); 92 | self.add_action(&quit_action); 93 | 94 | let about_action = gio::SimpleAction::new("about", None); 95 | about_action.connect_activate(clone!( 96 | #[weak(rename_to = app)] 97 | self, 98 | move |_, _| { 99 | app.show_about(); 100 | } 101 | )); 102 | self.add_action(&about_action); 103 | 104 | let preferences_action = gio::SimpleAction::new("preferences", None); 105 | preferences_action.connect_activate(clone!( 106 | #[weak(rename_to = app)] 107 | self, 108 | move |_, _| { 109 | let preferences_window = GameOfLifePreferencesWindow::new(); 110 | preferences_window.set_transient_for(app.active_window().as_ref()); 111 | preferences_window.set_modal(false); 112 | preferences_window.show(); 113 | } 114 | )); 115 | self.add_action(&preferences_action); 116 | 117 | let disable_design_hint_action = gio::SimpleAction::new("disable-design-hint", None); 118 | disable_design_hint_action.connect_activate(clone!( 119 | #[weak(rename_to = _app)] 120 | self, 121 | move |_, _| { 122 | GameOfLifeSettings::default().set_show_design_hint(false); 123 | } 124 | )); 125 | self.add_action(&disable_design_hint_action); 126 | } 127 | 128 | fn show_about(&self) { 129 | let window = self.active_window().unwrap(); 130 | let dialog = adw::AboutDialog::builder() 131 | .application_name("Game of Life") 132 | .developer_name("Andrea Coronese") 133 | .developers(vec!["Andrea Coronese"]) 134 | .copyright("© 2022 Andrea Coronese") 135 | .application_icon(APPLICATION_ID) 136 | .website("https://flathub.org/apps/details/com.github.sixpounder.GameOfLife") 137 | .issue_url("https://github.com/sixpounder/game-of-life/issues") 138 | .version(VERSION) 139 | .license_type(gtk::License::Gpl30) 140 | .translator_credits(translators_list().join("\n").as_str()) 141 | .build(); 142 | 143 | dialog.present(Some(&window)); 144 | } 145 | } 146 | 147 | -------------------------------------------------------------------------------- /src/widgets/universe_controls.rs: -------------------------------------------------------------------------------- 1 | use glib::prelude::*; 2 | use gtk::{gio, glib}; 3 | use gtk::{prelude::*, subclass::prelude::*, CompositeTemplate}; 4 | 5 | mod imp { 6 | use super::*; 7 | use glib::{ParamSpec, ParamSpecBoolean, ParamSpecString}; 8 | use once_cell::sync::Lazy; 9 | 10 | #[derive(Debug, Default, CompositeTemplate)] 11 | #[template(resource = "/com/github/sixpounder/GameOfLife/universe_controls.ui")] 12 | pub struct GameOfLifeUniverseControls { 13 | #[template_child] 14 | pub(super) run_button: TemplateChild, 15 | 16 | #[template_child] 17 | pub(super) random_seed_button: TemplateChild, 18 | 19 | pub(super) playing: std::cell::Cell, 20 | pub(super) reveal_tools: std::cell::Cell, 21 | pub(super) brush_mode: std::cell::Cell, 22 | } 23 | 24 | #[glib::object_subclass] 25 | impl ObjectSubclass for GameOfLifeUniverseControls { 26 | const NAME: &'static str = "GameOfLifeUniverseControls"; 27 | type Type = super::GameOfLifeUniverseControls; 28 | type ParentType = gtk::Widget; 29 | 30 | fn class_init(klass: &mut Self::Class) { 31 | Self::bind_template(klass); 32 | klass.set_layout_manager_type::(); 33 | } 34 | 35 | fn instance_init(obj: &glib::subclass::InitializingObject) { 36 | obj.init_template(); 37 | } 38 | } 39 | 40 | impl ObjectImpl for GameOfLifeUniverseControls { 41 | fn properties() -> &'static [ParamSpec] { 42 | static PROPERTIES: Lazy> = Lazy::new(|| { 43 | vec![ 44 | ParamSpecBoolean::builder("playing") 45 | .default_value(false) 46 | .readwrite() 47 | .build(), 48 | ParamSpecBoolean::builder("stopped") 49 | .default_value(true) 50 | .read_only() 51 | .build(), 52 | ParamSpecBoolean::builder("reveal-tools") 53 | .default_value(false) 54 | .readwrite() 55 | .build(), 56 | ParamSpecBoolean::builder("brush-mode") 57 | .default_value(false) 58 | .readwrite() 59 | .build(), 60 | ParamSpecString::builder("run-button-icon-name") 61 | .default_value(Some("media-playback-start-symbolic")) 62 | .readwrite() 63 | .build(), 64 | ] 65 | }); 66 | PROPERTIES.as_ref() 67 | } 68 | 69 | fn property(&self, _id: usize, pspec: &ParamSpec) -> glib::Value { 70 | let obj = self.obj(); 71 | let imp = obj.imp(); 72 | match pspec.name() { 73 | "playing" => imp.playing.get().to_value(), 74 | "stopped" => (!imp.playing.get()).to_value(), 75 | "reveal-tools" => imp.reveal_tools.get().to_value(), 76 | "brush-mode" => imp.brush_mode.get().to_value(), 77 | "run-button-icon-name" => match obj.property("playing") { 78 | true => "media-playback-stop-symbolic", 79 | false => "media-playback-start-symbolic", 80 | } 81 | .to_value(), 82 | _ => unimplemented!(), 83 | } 84 | } 85 | 86 | fn set_property(&self, _id: usize, value: &glib::Value, pspec: &ParamSpec) { 87 | let obj = self.obj(); 88 | match pspec.name() { 89 | "playing" => { 90 | let now_playing = value.get::().unwrap(); 91 | let was_playing = self.playing.get(); 92 | let run_button = self.run_button.get(); 93 | let run_button_style = run_button.style_context(); 94 | 95 | if now_playing != was_playing { 96 | self.playing.set(now_playing); 97 | 98 | if now_playing { 99 | run_button_style.remove_class("play"); 100 | run_button_style.add_class("stop"); 101 | } else { 102 | run_button_style.remove_class("stop"); 103 | run_button_style.add_class("play"); 104 | } 105 | 106 | obj.notify("run-button-icon-name"); 107 | obj.notify("playing"); 108 | obj.notify("stopped"); 109 | } 110 | } 111 | "reveal-tools" => { 112 | obj.imp().reveal_tools.set(value.get::().unwrap()); 113 | } 114 | _ => unimplemented!(), 115 | } 116 | } 117 | } 118 | 119 | impl WidgetImpl for GameOfLifeUniverseControls {} 120 | } 121 | 122 | glib::wrapper! { 123 | pub struct GameOfLifeUniverseControls(ObjectSubclass) 124 | @extends gtk::Widget, 125 | @implements gio::ActionGroup, gio::ActionMap, gtk::Root, gtk::Native, gtk::Buildable, gtk::ConstraintTarget, gtk::Accessible, gtk::ShortcutManager; 126 | } 127 | 128 | impl GameOfLifeUniverseControls { 129 | pub fn new>(application: &P) -> Self { 130 | glib::Object::builder() 131 | .property("application", application) 132 | .build() 133 | } 134 | 135 | pub fn set_tools_revealed(&self, value: bool) { 136 | self.imp().reveal_tools.set(value); 137 | self.notify("reveal-tools"); 138 | } 139 | 140 | pub fn tools_revealed(&self) -> bool { 141 | self.imp().reveal_tools.get() 142 | } 143 | 144 | pub fn toggle_brush(&self) { 145 | self.imp().brush_mode.set(!self.brush()); 146 | self.notify("brush-mode"); 147 | } 148 | 149 | pub fn brush(&self) -> bool { 150 | self.imp().brush_mode.get() 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/widgets/new_universe_view.rs: -------------------------------------------------------------------------------- 1 | use crate::{config::G_LOG_DOMAIN, services::GameOfLifeSettings}; 2 | use gtk::{gio, glib, glib::clone}; 3 | use gtk::{prelude::*, subclass::prelude::*, CompositeTemplate}; 4 | 5 | #[derive(Debug, Clone, Copy)] 6 | #[repr(u8)] 7 | pub enum NewUniverseType { 8 | Empty, 9 | Random, 10 | Template(&'static str), 11 | } 12 | 13 | impl Default for NewUniverseType { 14 | fn default() -> Self { 15 | NewUniverseType::Empty 16 | } 17 | } 18 | 19 | mod imp { 20 | use super::*; 21 | use glib::{ParamSpec, ParamSpecBoolean}; 22 | use once_cell::sync::Lazy; 23 | 24 | #[derive(Debug, Default, CompositeTemplate)] 25 | #[template(resource = "/com/github/sixpounder/GameOfLife/new_universe_view.ui")] 26 | pub struct GameOfLifeNewUniverseView { 27 | #[template_child] 28 | pub(super) rows_entry: TemplateChild, 29 | #[template_child] 30 | pub(super) columns_entry: TemplateChild, 31 | #[template_child] 32 | pub(super) empty_check: TemplateChild, 33 | #[template_child] 34 | pub(super) random_check: TemplateChild, 35 | #[template_child] 36 | pub(super) template_check: TemplateChild, 37 | #[template_child] 38 | pub(super) template_list_dropdown: TemplateChild, 39 | } 40 | 41 | #[glib::object_subclass] 42 | impl ObjectSubclass for GameOfLifeNewUniverseView { 43 | const NAME: &'static str = "GameOfLifeNewUniverseView"; 44 | type Type = super::GameOfLifeNewUniverseView; 45 | type ParentType = gtk::Dialog; 46 | 47 | fn class_init(klass: &mut Self::Class) { 48 | Self::bind_template(klass); 49 | } 50 | 51 | fn instance_init(obj: &glib::subclass::InitializingObject) { 52 | obj.init_template(); 53 | } 54 | } 55 | 56 | impl ObjectImpl for GameOfLifeNewUniverseView { 57 | fn constructed(&self) { 58 | self.parent_constructed(); 59 | let obj = self.obj(); 60 | obj.setup_widgets(); 61 | obj.connect_events(); 62 | } 63 | 64 | fn properties() -> &'static [ParamSpec] { 65 | static PROPERTIES: Lazy> = Lazy::new(|| { 66 | vec![ParamSpecBoolean::builder("dimensions-editable") 67 | .default_value(false) 68 | .read_only() 69 | .build()] 70 | }); 71 | PROPERTIES.as_ref() 72 | } 73 | 74 | fn property(&self, _id: usize, pspec: &ParamSpec) -> glib::Value { 75 | let obj = self.obj(); 76 | match pspec.name() { 77 | "dimensions-editable" => { 78 | (!matches!(obj.option(), NewUniverseType::Template(_))).to_value() 79 | } 80 | _ => unimplemented!(), 81 | } 82 | } 83 | } 84 | 85 | impl WidgetImpl for GameOfLifeNewUniverseView {} 86 | impl WindowImpl for GameOfLifeNewUniverseView {} 87 | impl DialogImpl for GameOfLifeNewUniverseView {} 88 | } 89 | 90 | glib::wrapper! { 91 | pub struct GameOfLifeNewUniverseView(ObjectSubclass) 92 | @extends gtk::Widget, gtk::Window, gtk::Dialog, 93 | @implements gio::ActionGroup, gio::ActionMap, gtk::Root, gtk::Native, gtk::Buildable, gtk::ConstraintTarget, gtk::Accessible, gtk::ShortcutManager; 94 | } 95 | 96 | impl Default for GameOfLifeNewUniverseView { 97 | fn default() -> Self { 98 | Self::new() 99 | } 100 | } 101 | 102 | impl GameOfLifeNewUniverseView { 103 | pub fn new() -> Self { 104 | glib::Object::new::() 105 | } 106 | 107 | fn setup_widgets(&self) { 108 | let settings = GameOfLifeSettings::default(); 109 | 110 | let row_adjust = gtk::Adjustment::builder() 111 | .lower(10.) 112 | .upper(1000.) 113 | .step_increment(1.0) 114 | .page_increment(10.) 115 | .value(settings.universe_width().into()) 116 | .build(); 117 | 118 | let column_adjust = gtk::Adjustment::builder() 119 | .lower(10.) 120 | .upper(1000.) 121 | .step_increment(1.0) 122 | .page_increment(10.) 123 | .value(settings.universe_height().into()) 124 | .build(); 125 | 126 | row_adjust.connect_notify_local( 127 | Some("value"), 128 | clone!( 129 | #[strong] 130 | settings, 131 | move |adj, _| { 132 | settings.set_universe_width(adj.value() as i32); 133 | } 134 | ), 135 | ); 136 | 137 | column_adjust.connect_notify_local( 138 | Some("value"), 139 | clone!( 140 | #[strong] 141 | settings, 142 | move |adj, _| { 143 | settings.set_universe_height(adj.value() as i32); 144 | } 145 | ), 146 | ); 147 | self.imp().rows_entry.set_adjustment(&row_adjust); 148 | self.imp().columns_entry.set_adjustment(&column_adjust); 149 | 150 | self.imp() 151 | .template_list_dropdown 152 | .set_sensitive(self.imp().template_check.is_active()); 153 | } 154 | 155 | fn connect_events(&self) { 156 | self.imp().template_check.connect_toggled(clone!( 157 | #[strong(rename_to = this)] 158 | self, 159 | move |widget| { 160 | this.imp() 161 | .template_list_dropdown 162 | .set_sensitive(widget.is_active()); 163 | this.notify("dimensions-editable"); 164 | } 165 | )); 166 | } 167 | 168 | pub fn option(&self) -> NewUniverseType { 169 | if self.imp().empty_check.is_active() { 170 | NewUniverseType::Empty 171 | } else if self.imp().random_check.is_active() { 172 | NewUniverseType::Random 173 | } else { 174 | let selected_template_object = self 175 | .imp() 176 | .template_list_dropdown 177 | .selected_item() 178 | .expect("How?") 179 | .downcast::() 180 | .expect("How?") 181 | .string(); 182 | glib::g_debug!( 183 | G_LOG_DOMAIN, 184 | "Selected {} template", 185 | selected_template_object.as_str() 186 | ); 187 | match selected_template_object.as_str() { 188 | "Glider" => NewUniverseType::Template("glider"), 189 | "Pulsar" => NewUniverseType::Template("pulsar"), 190 | "Circle of fire" => NewUniverseType::Template("circle_of_fire"), 191 | "Quadpole" => NewUniverseType::Template("quadpole"), 192 | "Spaceship" => NewUniverseType::Template("spaceship"), 193 | _ => unreachable!("This should not happen"), 194 | } 195 | } 196 | } 197 | 198 | pub fn size(&self) -> (f64, f64) { 199 | ( 200 | self.imp().rows_entry.value(), 201 | self.imp().columns_entry.value(), 202 | ) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /data/com.github.sixpounder.GameOfLife.appdata.xml.in.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | @APPLICATION_ID@ 4 | CC0-1.0 5 | GPL-3.0-or-later 6 | Game of Life 7 |

Play Conway's Game of Life 8 | 9 |

10 | Game of Life lets you simulate simple universes made of cells that can be 11 | alive or dead, and evolve according to simple rules. 12 |

13 |

14 | Current features: 15 |

16 |
    17 |
  • Random seed universes
  • 18 |
  • Provide start templates
  • 19 |
  • Manually edit universes
  • 20 |
  • Save and restore snapshots
  • 21 |
22 |
23 | 24 | 25 | https://raw.githubusercontent.com/sixpounder/game-of-life/main/data/screenshots/1.png 26 | 27 | 28 | https://raw.githubusercontent.com/sixpounder/game-of-life/main/data/screenshots/2.png 29 | 30 | 31 | https://raw.githubusercontent.com/sixpounder/game-of-life/main/data/screenshots/3.png 32 | 33 | 34 | https://raw.githubusercontent.com/sixpounder/game-of-life/main/data/screenshots/4.png 35 | 36 | 37 | @APPLICATION_ID@.desktop 38 | https://github.com/sixpounder/game-of-life 39 | https://github.com/sixpounder/game-of-life/issues 40 | https://github.com/sixpounder/game-of-life 41 | Andrea Coronese 42 | sixpounder_at_protonmail.com 43 | game-of-life 44 | 45 | 46 | 600 47 | 48 | 49 | keyboard 50 | pointing 51 | 52 | 53 | @APPLICATION_ID@.desktop 54 | 55 | 56 | 57 |

This release updates Gnome runtime to version 49

58 |
59 |
60 | 61 | 62 |

This release updates GTK stack dependencies as well as Gnome runtime to version 44

63 |
64 |
65 | 66 | 67 |

Maintenace release

68 |
    69 |
  • 70 | Better italian translation 71 |
  • 72 |
  • 73 | Fix spdx / attributions etc 74 |
  • 75 |
76 |
77 |
78 | 79 | 80 |

This release addresses the followings:

81 |
    82 |
  • 83 | More consistent UI 84 |
  • 85 |
  • 86 | Dutch translations (thanks Philip Goto) 87 |
  • 88 |
89 |
90 |
91 | 92 | 93 |

This release addresses the followings:

94 |
    95 |
  • 96 | Feature: step forward one generation 97 |
  • 98 |
  • 99 | Group design tools in revealer 100 |
  • 101 |
102 |
103 |
104 | 105 | 106 |

This release addresses the followings:

107 |
    108 |
  • 109 | New icon (thanks to Tobias Bernard) 110 |
  • 111 |
  • 112 | Reduce close button size 113 |
  • 114 |
115 |
116 |
117 | 118 | 119 |

This release addresses the followings:

120 |
    121 |
  • 122 | Fixes main menu button shape 123 |
  • 124 |
  • 125 | Fixes a few problems with the main menu entries 126 |
  • 127 |
  • 128 | Layout changes: Moves main menu to the left of the window, introduce close button to the right 129 |
  • 130 |
131 |
132 |
133 | 134 | 135 |

This release addresses the followings:

136 |
    137 |
  • 138 | Fixes templates not being loaded 139 |
  • 140 |
  • 141 | Moves grid rendering to gtk4 render node api 142 |
  • 143 |
144 |
145 |
146 | 147 | 148 |

This release addresses the followings:

149 |
    150 |
  • 151 | Allow for cells fade out when they die 152 |
  • 153 |
  • 154 | Performance issues on edge cases 155 |
  • 156 |
  • 157 | gtk4/glib/libadwaita stack upgrade 158 |
  • 159 |
160 |
161 |
162 | 163 | 164 |

Translations:

165 |
    166 |
  • Add french translation (Rene Coty)
  • 167 |
168 |
169 |
170 | 171 | 172 |

This is a revision addressing a few problems

173 |
    174 |
  • Fix interaction bugs
  • 175 |
  • Minor performance tweaks
  • 176 |
177 |
178 |
179 | 180 |
181 | 182 | 183 | -------------------------------------------------------------------------------- /data/icons/hicolor/scalable/apps/com.github.sixpounder.GameOfLife.Devel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/widgets/preferences_window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 154 | 155 | 1 156 | 100 157 | 1 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /src/widgets/preferences_window.rs: -------------------------------------------------------------------------------- 1 | use crate::services::GameOfLifeSettings; 2 | use adw::{ 3 | subclass::{preferences_window::PreferencesWindowImpl, window::AdwWindowImpl}, 4 | PreferencesWindow, 5 | }; 6 | use gtk::{gdk::RGBA, gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate}; 7 | 8 | mod imp { 9 | use super::*; 10 | use glib::{ParamSpec, ParamSpecString}; 11 | use once_cell::sync::Lazy; 12 | 13 | #[derive(Debug, Default, CompositeTemplate)] 14 | #[template(resource = "/com/github/sixpounder/GameOfLife/preferences_window.ui")] 15 | pub struct GameOfLifePreferencesWindow { 16 | #[template_child] 17 | pub(super) evolution_speed: TemplateChild, 18 | 19 | #[template_child] 20 | pub(super) cell_color_picker: TemplateChild, 21 | 22 | #[template_child] 23 | pub(super) background_color_picker: TemplateChild, 24 | 25 | #[template_child] 26 | pub(super) cell_color_dark_picker: TemplateChild, 27 | 28 | #[template_child] 29 | pub(super) background_color_dark_picker: TemplateChild, 30 | 31 | #[template_child] 32 | pub(super) draw_cells_outline: TemplateChild, 33 | 34 | #[template_child] 35 | pub(super) fade_out_dead_cells: TemplateChild, 36 | 37 | #[template_child] 38 | pub(super) allow_render_on_resize: TemplateChild, 39 | 40 | #[template_child] 41 | pub(super) evolution_speed_adjustment: TemplateChild, 42 | 43 | #[template_child] 44 | pub(super) show_design_hint: TemplateChild, 45 | } 46 | 47 | #[glib::object_subclass] 48 | impl ObjectSubclass for GameOfLifePreferencesWindow { 49 | const NAME: &'static str = "GameOfLifePreferencesWindow"; 50 | type Type = super::GameOfLifePreferencesWindow; 51 | type ParentType = PreferencesWindow; 52 | 53 | fn class_init(klass: &mut Self::Class) { 54 | Self::bind_template(klass); 55 | } 56 | 57 | fn instance_init(obj: &glib::subclass::InitializingObject) { 58 | obj.init_template(); 59 | } 60 | } 61 | 62 | impl ObjectImpl for GameOfLifePreferencesWindow { 63 | fn constructed(&self) { 64 | self.parent_constructed(); 65 | self.obj().setup_bindings(); 66 | } 67 | 68 | fn properties() -> &'static [glib::ParamSpec] { 69 | static PROPERTIES: Lazy> = Lazy::new(|| { 70 | vec![ 71 | ParamSpecString::builder("universe-cell-color") 72 | .readwrite() 73 | .default_value(None) 74 | .build(), 75 | ParamSpecString::builder("universe-background-color") 76 | .default_value(None) 77 | .readwrite() 78 | .build(), 79 | ParamSpecString::builder("universe-cell-color-dark") 80 | .default_value(None) 81 | .readwrite() 82 | .build(), 83 | ParamSpecString::builder("universe-background-color-dark") 84 | .default_value(None) 85 | .readwrite() 86 | .build(), 87 | ] 88 | }); 89 | PROPERTIES.as_ref() 90 | } 91 | 92 | fn set_property(&self, _id: usize, value: &glib::Value, pspec: &ParamSpec) { 93 | match pspec.name() { 94 | "universe-cell-color" => { 95 | let str_value = value.get::().unwrap(); 96 | let rgba_value = RGBA::parse(str_value.as_str()).unwrap(); 97 | self.cell_color_picker.set_rgba(&rgba_value); 98 | } 99 | "universe-background-color" => { 100 | let str_value = value.get::().unwrap(); 101 | let rgba_value = RGBA::parse(str_value.as_str()).unwrap(); 102 | self.background_color_picker.set_rgba(&rgba_value); 103 | } 104 | "universe-cell-color-dark" => { 105 | let str_value = value.get::().unwrap(); 106 | let rgba_value = RGBA::parse(str_value.as_str()).unwrap(); 107 | self.cell_color_dark_picker.set_rgba(&rgba_value); 108 | } 109 | "universe-background-color-dark" => { 110 | let str_value = value.get::().unwrap(); 111 | let rgba_value = RGBA::parse(str_value.as_str()).unwrap(); 112 | self.background_color_dark_picker.set_rgba(&rgba_value); 113 | } 114 | _ => unimplemented!(), 115 | } 116 | } 117 | 118 | fn property(&self, _id: usize, pspec: &ParamSpec) -> glib::Value { 119 | match pspec.name() { 120 | "universe-cell-color" => self.cell_color_picker.rgba().to_string().to_value(), 121 | "universe-background-color" => { 122 | self.background_color_picker.rgba().to_string().to_value() 123 | } 124 | "universe-cell-color-dark" => { 125 | self.cell_color_dark_picker.rgba().to_string().to_value() 126 | } 127 | "universe-background-color-dark" => self 128 | .background_color_dark_picker 129 | .rgba() 130 | .to_string() 131 | .to_value(), 132 | _ => unimplemented!(), 133 | } 134 | } 135 | } 136 | 137 | impl WidgetImpl for GameOfLifePreferencesWindow {} 138 | impl WindowImpl for GameOfLifePreferencesWindow {} 139 | impl AdwWindowImpl for GameOfLifePreferencesWindow {} 140 | impl PreferencesWindowImpl for GameOfLifePreferencesWindow {} 141 | } 142 | 143 | glib::wrapper! { 144 | pub struct GameOfLifePreferencesWindow(ObjectSubclass) 145 | @extends gtk::Widget, gtk::Window, adw::Window, adw::PreferencesWindow, 146 | @implements gio::ActionGroup, gio::ActionMap, gtk::Root, gtk::Native, gtk::Buildable, gtk::ConstraintTarget, gtk::Accessible, gtk::ShortcutManager; 147 | } 148 | 149 | impl Default for GameOfLifePreferencesWindow { 150 | fn default() -> Self { 151 | Self::new() 152 | } 153 | } 154 | 155 | impl GameOfLifePreferencesWindow { 156 | pub fn new() -> Self { 157 | glib::Object::builder().build() 158 | } 159 | 160 | fn setup_bindings(&self) { 161 | let settings = GameOfLifeSettings::default(); 162 | let imp = self.imp(); 163 | let instance = imp.obj(); 164 | 165 | settings.bind( 166 | "draw-cells-outline", 167 | &imp.draw_cells_outline.get(), 168 | "active", 169 | ); 170 | settings.bind("fade-out-cells", &imp.fade_out_dead_cells.get(), "active"); 171 | settings.bind( 172 | "allow-render-during-resize", 173 | &imp.allow_render_on_resize.get(), 174 | "active", 175 | ); 176 | settings.bind("show-design-hint", &imp.show_design_hint.get(), "active"); 177 | settings.bind( 178 | "evolution-speed", 179 | &imp.evolution_speed_adjustment.get(), 180 | "value", 181 | ); 182 | 183 | // Proxy colors to this widget, to convert from RGBA to string 184 | settings.bind("fg-color", instance.as_ref(), "universe-cell-color"); 185 | settings.bind("bg-color", instance.as_ref(), "universe-background-color"); 186 | settings.bind( 187 | "fg-color-dark", 188 | instance.as_ref(), 189 | "universe-cell-color-dark", 190 | ); 191 | settings.bind( 192 | "bg-color-dark", 193 | instance.as_ref(), 194 | "universe-background-color-dark", 195 | ); 196 | 197 | // Listen for color pickers 198 | 199 | imp.cell_color_picker.connect_color_set(glib::clone!( 200 | #[strong(rename_to = this)] 201 | self, 202 | move |picker| { 203 | this.set_property("universe-cell-color", picker.rgba().to_string().to_value()); 204 | } 205 | )); 206 | 207 | imp.background_color_picker.connect_color_set(glib::clone!( 208 | #[strong(rename_to = this)] 209 | self, 210 | move |picker| { 211 | this.set_property( 212 | "universe-background-color", 213 | picker.rgba().to_string().to_value(), 214 | ); 215 | } 216 | )); 217 | 218 | imp.cell_color_dark_picker.connect_color_set(glib::clone!( 219 | #[strong(rename_to = this)] 220 | self, 221 | move |picker| { 222 | this.set_property( 223 | "universe-cell-color-dark", 224 | picker.rgba().to_string().to_value(), 225 | ); 226 | } 227 | )); 228 | 229 | imp.background_color_dark_picker 230 | .connect_color_set(glib::clone!( 231 | #[strong(rename_to = this)] 232 | self, 233 | move |picker| { 234 | this.set_property( 235 | "universe-background-color-dark", 236 | picker.rgba().to_string().to_value(), 237 | ); 238 | } 239 | )); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/widgets/universe_controls.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 166 | 167 |
168 | 169 | _New Universe 170 | win.new 171 | 172 | 173 | _Open Snapshot 174 | win.open-snapshot 175 | 176 | 177 | _Save Snapshot 178 | win.snapshot 179 | 180 |
181 |
182 | 183 | _Preferences 184 | app.preferences 185 | 186 | 187 | _Keyboard Shortcuts 188 | win.show-help-overlay 189 | 190 | 191 | _About Game of Life 192 | app.about 193 | 194 | 195 | _Close 196 | app.quit 197 | 198 |
199 |
200 |
201 | 202 | -------------------------------------------------------------------------------- /po/game-of-life.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the game-of-life package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: game-of-life\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2023-03-03 15:13+0100\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=CHARSET\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:3 21 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:6 22 | msgid "Game of Life" 23 | msgstr "" 24 | 25 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:4 26 | msgid "Game of Life Simulator" 27 | msgstr "" 28 | 29 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:12 30 | msgid "simulation;game;" 31 | msgstr "" 32 | 33 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:7 34 | msgid "Play Conway's Game of Life" 35 | msgstr "" 36 | 37 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:9 38 | msgid "" 39 | "Game of Life lets you simulate simple universes made of cells that can be " 40 | "alive or dead, and evolve according to simple rules." 41 | msgstr "" 42 | 43 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:13 44 | msgid "Current features:" 45 | msgstr "" 46 | 47 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:17 48 | msgid "Random seed universes" 49 | msgstr "" 50 | 51 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:18 52 | msgid "Provide start templates" 53 | msgstr "" 54 | 55 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:19 56 | msgid "Manually edit universes" 57 | msgstr "" 58 | 59 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:20 60 | msgid "Save and restore snapshots" 61 | msgstr "" 62 | 63 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:39 64 | msgid "Andrea Coronese" 65 | msgstr "" 66 | 67 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:55 68 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:68 69 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:81 70 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:94 71 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:110 72 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:123 73 | msgid "This release addresses the followings:" 74 | msgstr "" 75 | 76 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:57 77 | msgid "More consistent UI" 78 | msgstr "" 79 | 80 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:60 81 | msgid "Dutch translations (thanks Philip Goto)" 82 | msgstr "" 83 | 84 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:70 85 | msgid "Feature: step forward one generation" 86 | msgstr "" 87 | 88 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:73 89 | msgid "Group design tools in revealer" 90 | msgstr "" 91 | 92 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:83 93 | msgid "New icon (thanks to Tobias Bernard)" 94 | msgstr "" 95 | 96 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:86 97 | msgid "Reduce close button size" 98 | msgstr "" 99 | 100 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:96 101 | msgid "Fixes main menu button shape" 102 | msgstr "" 103 | 104 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:99 105 | msgid "Fixes a few problems with the main menu entries" 106 | msgstr "" 107 | 108 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:103 109 | msgid "Layout changes" 110 | msgstr "" 111 | 112 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:112 113 | msgid "Fixes templates not being loaded" 114 | msgstr "" 115 | 116 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:115 117 | msgid "Moves grid rendering to gtk4 render node api" 118 | msgstr "" 119 | 120 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:125 121 | msgid "Allow for cells fade out when they die" 122 | msgstr "" 123 | 124 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:128 125 | msgid "Performance issues on edge cases" 126 | msgstr "" 127 | 128 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:131 129 | msgid "gtk4/glib/libadwaita stack upgrade" 130 | msgstr "" 131 | 132 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:139 133 | msgid "Translations:" 134 | msgstr "" 135 | 136 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:141 137 | msgid "Add french translation (Rene Coty)" 138 | msgstr "" 139 | 140 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:147 141 | msgid "This is a revision addressing a few problems" 142 | msgstr "" 143 | 144 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:149 145 | msgid "Fix interaction bugs" 146 | msgstr "" 147 | 148 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:150 149 | msgid "Minor performance tweaks" 150 | msgstr "" 151 | 152 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:18 153 | msgid "Fades out cells when they die instead of deleting them in one go" 154 | msgstr "" 155 | 156 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:22 157 | msgid "" 158 | "The number of generations per seconds that should be computed when a " 159 | "simulation is running" 160 | msgstr "" 161 | 162 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:32 163 | msgid "The width of the universe being generated, in cells number" 164 | msgstr "" 165 | 166 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:36 167 | msgid "The height of the universe being generated, in cells number" 168 | msgstr "" 169 | 170 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:40 171 | msgid "Wheter to draw cells outline in universe grid" 172 | msgstr "" 173 | 174 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:44 175 | msgid "" 176 | "Wheter to allow universe rendering when the application window is resizing" 177 | msgstr "" 178 | 179 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:48 180 | msgid "Wheter to show an interaction hint on design mode activated" 181 | msgstr "" 182 | 183 | #: src/gtk/help-overlay.ui:11 184 | msgctxt "shortcut window" 185 | msgid "General" 186 | msgstr "" 187 | 188 | #: src/gtk/help-overlay.ui:14 189 | msgctxt "shortcut window" 190 | msgid "New Universe" 191 | msgstr "" 192 | 193 | #: src/gtk/help-overlay.ui:20 194 | msgctxt "shortcut window" 195 | msgid "Open Snapshot" 196 | msgstr "" 197 | 198 | #: src/gtk/help-overlay.ui:26 199 | msgctxt "shortcut window" 200 | msgid "Save Snapshot" 201 | msgstr "" 202 | 203 | #: src/gtk/help-overlay.ui:32 204 | msgctxt "shortcut window" 205 | msgid "Preferences" 206 | msgstr "" 207 | 208 | #: src/gtk/help-overlay.ui:38 209 | msgctxt "shortcut window" 210 | msgid "Show Shortcuts" 211 | msgstr "" 212 | 213 | #: src/gtk/help-overlay.ui:44 214 | msgctxt "shortcut window" 215 | msgid "Close" 216 | msgstr "" 217 | 218 | #: src/gtk/help-overlay.ui:52 219 | msgctxt "shortcut window" 220 | msgid "Universe Control" 221 | msgstr "" 222 | 223 | #: src/gtk/help-overlay.ui:55 224 | msgctxt "shortcut window" 225 | msgid "Toggle Design Mode" 226 | msgstr "" 227 | 228 | #: src/gtk/help-overlay.ui:61 229 | msgctxt "shortcut window" 230 | msgid "Toggle Run Universe" 231 | msgstr "" 232 | 233 | #: src/gtk/help-overlay.ui:67 234 | msgctxt "shortcut window" 235 | msgid "Seed Universe" 236 | msgstr "" 237 | 238 | #: src/window.rs:317 239 | msgid "Left click to make a cell alive, right click to make it dead" 240 | msgstr "" 241 | 242 | #: src/window.rs:320 243 | msgid "Do not show again" 244 | msgstr "" 245 | 246 | #: src/window.rs:340 247 | msgid "_Save" 248 | msgstr "" 249 | 250 | #: src/window.rs:341 src/window.rs:399 251 | msgid "_Cancel" 252 | msgstr "" 253 | 254 | #: src/window.rs:343 255 | msgid "Save universe snapshot" 256 | msgstr "" 257 | 258 | #: src/window.rs:368 259 | msgid "Unable to write to file" 260 | msgstr "" 261 | 262 | #: src/window.rs:374 263 | msgid "Unable to serialize snapshot" 264 | msgstr "" 265 | 266 | #: src/window.rs:398 267 | msgid "_Open" 268 | msgstr "" 269 | 270 | #: src/window.rs:401 271 | msgid "Open universe snapshot" 272 | msgstr "" 273 | 274 | #: src/window.rs:430 src/window.rs:436 275 | msgid "Unreadable file" 276 | msgstr "" 277 | 278 | #: src/window.rs:441 279 | msgid "File not existing or not accessible" 280 | msgstr "" 281 | 282 | #: src/window.rs:483 283 | msgid "Bad template data" 284 | msgstr "" 285 | 286 | #: src/window.rs:489 287 | msgid "Template not found" 288 | msgstr "" 289 | 290 | #: src/widgets/universe_controls.ui:53 291 | msgctxt "a11y" 292 | msgid "Toggle design mode" 293 | msgstr "" 294 | 295 | #: src/widgets/universe_controls.ui:62 296 | msgid "Toggle design tools" 297 | msgstr "" 298 | 299 | #: src/widgets/universe_controls.ui:74 300 | msgid "Cell brush" 301 | msgstr "" 302 | 303 | #: src/widgets/universe_controls.ui:80 304 | msgctxt "a11y" 305 | msgid "Cell brush" 306 | msgstr "" 307 | 308 | #: src/widgets/universe_controls.ui:87 309 | msgid "Randomly seed this universe" 310 | msgstr "" 311 | 312 | #: src/widgets/universe_controls.ui:97 313 | msgctxt "a11y" 314 | msgid "Randomly seed this universe" 315 | msgstr "" 316 | 317 | #: src/widgets/universe_controls.ui:110 318 | msgid "Toggle universe run" 319 | msgstr "" 320 | 321 | #: src/widgets/universe_controls.ui:118 322 | msgctxt "a11y" 323 | msgid "Toggle universe run" 324 | msgstr "" 325 | 326 | #: src/widgets/universe_controls.ui:125 327 | msgid "Skip forward one generation" 328 | msgstr "" 329 | 330 | #: src/widgets/universe_controls.ui:135 331 | msgctxt "a11y" 332 | msgid "Skip forward one generation" 333 | msgstr "" 334 | 335 | #: src/widgets/universe_controls.ui:169 336 | msgid "_New Universe" 337 | msgstr "" 338 | 339 | #: src/widgets/universe_controls.ui:173 340 | msgid "_Open Snapshot" 341 | msgstr "" 342 | 343 | #: src/widgets/universe_controls.ui:177 344 | msgid "_Save Snapshot" 345 | msgstr "" 346 | 347 | #: src/widgets/universe_controls.ui:183 348 | msgid "_Preferences" 349 | msgstr "" 350 | 351 | #: src/widgets/universe_controls.ui:187 352 | msgid "_Keyboard Shortcuts" 353 | msgstr "" 354 | 355 | #: src/widgets/universe_controls.ui:191 356 | msgid "_About Game of Life" 357 | msgstr "" 358 | 359 | #: src/widgets/universe_controls.ui:195 360 | msgid "_Close" 361 | msgstr "" 362 | 363 | #: src/widgets/new_universe_view.ui:4 364 | msgid "New universe" 365 | msgstr "" 366 | 367 | #: src/widgets/new_universe_view.ui:36 368 | msgid "Empty universe" 369 | msgstr "" 370 | 371 | #: src/widgets/new_universe_view.ui:42 372 | msgid "Random seed" 373 | msgstr "" 374 | 375 | #: src/widgets/new_universe_view.ui:53 376 | msgid "Template" 377 | msgstr "" 378 | 379 | #: src/widgets/new_universe_view.ui:64 380 | msgid "Glider" 381 | msgstr "" 382 | 383 | #: src/widgets/new_universe_view.ui:65 384 | msgid "Pulsar" 385 | msgstr "" 386 | 387 | #: src/widgets/new_universe_view.ui:66 388 | msgid "Quadpole" 389 | msgstr "" 390 | 391 | #: src/widgets/new_universe_view.ui:67 392 | msgid "Spaceship" 393 | msgstr "" 394 | 395 | #: src/widgets/new_universe_view.ui:68 396 | msgid "Circle of fire" 397 | msgstr "" 398 | 399 | #: src/widgets/new_universe_view.ui:80 400 | msgid "Cancel" 401 | msgstr "" 402 | 403 | #: src/widgets/new_universe_view.ui:89 404 | msgid "Create" 405 | msgstr "" 406 | 407 | #: src/widgets/preferences_window.ui:6 408 | msgid "General" 409 | msgstr "" 410 | 411 | #: src/widgets/preferences_window.ui:10 412 | msgid "Feedbacks" 413 | msgstr "" 414 | 415 | #: src/widgets/preferences_window.ui:11 416 | msgid "Various application feedbacks settings" 417 | msgstr "" 418 | 419 | #: src/widgets/preferences_window.ui:14 420 | msgid "Design hint" 421 | msgstr "" 422 | 423 | #: src/widgets/preferences_window.ui:16 424 | msgid "Show a toast describing interaction modes during design mode" 425 | msgstr "" 426 | 427 | #: src/widgets/preferences_window.ui:32 428 | msgid "Universe" 429 | msgstr "" 430 | 431 | #: src/widgets/preferences_window.ui:36 432 | msgid "Appearance" 433 | msgstr "" 434 | 435 | #: src/widgets/preferences_window.ui:39 436 | msgid "Light colors" 437 | msgstr "" 438 | 439 | #: src/widgets/preferences_window.ui:40 440 | msgid "" 441 | "These colors are applied if you use a light scheme color on your desktop" 442 | msgstr "" 443 | 444 | #: src/widgets/preferences_window.ui:64 445 | msgid "Dark colors" 446 | msgstr "" 447 | 448 | #: src/widgets/preferences_window.ui:65 449 | msgid "These colors are applied if you use a dark scheme color on your desktop" 450 | msgstr "" 451 | 452 | #: src/widgets/preferences_window.ui:89 453 | msgid "Draw cells outline" 454 | msgstr "" 455 | 456 | #: src/widgets/preferences_window.ui:102 457 | msgid "Fade out dead cells" 458 | msgstr "" 459 | 460 | #: src/widgets/preferences_window.ui:115 461 | msgid "Render on resize" 462 | msgstr "" 463 | 464 | #: src/widgets/preferences_window.ui:118 465 | msgid "" 466 | "Allows rendering the grid during a resize event of the application window. " 467 | "May affect performance." 468 | msgstr "" 469 | 470 | #: src/widgets/preferences_window.ui:133 471 | msgid "Evolution" 472 | msgstr "" 473 | 474 | #: src/widgets/preferences_window.ui:136 475 | msgid "Evolutions speed" 476 | msgstr "" 477 | 478 | #: src/widgets/preferences_window.ui:138 479 | msgid "The number of generations to be computed per second during an evolution" 480 | msgstr "" 481 | -------------------------------------------------------------------------------- /po/zh_CN.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the game-of-life package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: game-of-life\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2023-03-03 15:13+0100\n" 12 | "PO-Revision-Date: 2024-08-14 00:48+0800\n" 13 | "Last-Translator: SuGotLand 苏革岚 \n" 14 | "Language-Team: \n" 15 | "Language: zh_CN\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "X-Generator: Poedit 3.4.2\n" 20 | 21 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:3 22 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:6 23 | msgid "Game of Life" 24 | msgstr "生命游戏" 25 | 26 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:4 27 | msgid "Game of Life Simulator" 28 | msgstr "生命游戏模拟器" 29 | 30 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:12 31 | msgid "simulation;game;" 32 | msgstr "simulation;game;模拟器;游戏;" 33 | 34 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:7 35 | msgid "Play Conway's Game of Life" 36 | msgstr "播放 Conway 的生命游戏" 37 | 38 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:9 39 | msgid "" 40 | "Game of Life lets you simulate simple universes made of cells that can be " 41 | "alive or dead, and evolve according to simple rules." 42 | msgstr "" 43 | "生命游戏让你你模拟由细胞组成的简单宇宙,这些细胞可生可死,并按照简单的规则进" 44 | "化。" 45 | 46 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:13 47 | msgid "Current features:" 48 | msgstr "目前的功能:" 49 | 50 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:17 51 | msgid "Random seed universes" 52 | msgstr "随机种子宇宙" 53 | 54 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:18 55 | msgid "Provide start templates" 56 | msgstr "提供起始模板" 57 | 58 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:19 59 | msgid "Manually edit universes" 60 | msgstr "手动编辑宇宙" 61 | 62 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:20 63 | msgid "Save and restore snapshots" 64 | msgstr "保存和恢复快照" 65 | 66 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:39 67 | msgid "Andrea Coronese" 68 | msgstr "Andrea Coronese" 69 | 70 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:55 71 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:68 72 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:81 73 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:94 74 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:110 75 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:123 76 | msgid "This release addresses the followings:" 77 | msgstr "本版本涉及以下内容:" 78 | 79 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:57 80 | msgid "More consistent UI" 81 | msgstr "更加一致的用户界面" 82 | 83 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:60 84 | msgid "Dutch translations (thanks Philip Goto)" 85 | msgstr "荷兰语译文(感谢 Philip Goto)" 86 | 87 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:70 88 | msgid "Feature: step forward one generation" 89 | msgstr "特点:向前迈进一代" 90 | 91 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:73 92 | msgid "Group design tools in revealer" 93 | msgstr "揭示器中的群组设计工具" 94 | 95 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:83 96 | msgid "New icon (thanks to Tobias Bernard)" 97 | msgstr "新图标(感谢 Tobias Bernard)" 98 | 99 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:86 100 | msgid "Reduce close button size" 101 | msgstr "缩小关闭按钮的尺寸" 102 | 103 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:96 104 | msgid "Fixes main menu button shape" 105 | msgstr "修正主菜单按钮形状" 106 | 107 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:99 108 | msgid "Fixes a few problems with the main menu entries" 109 | msgstr "修复了主菜单条目中的一些问题" 110 | 111 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:103 112 | msgid "Layout changes" 113 | msgstr "布局更改" 114 | 115 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:112 116 | msgid "Fixes templates not being loaded" 117 | msgstr "修复模板无法加载的问题" 118 | 119 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:115 120 | msgid "Moves grid rendering to gtk4 render node api" 121 | msgstr "将grid渲染更改为gtk4渲染" 122 | 123 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:125 124 | msgid "Allow for cells fade out when they die" 125 | msgstr "允许细胞在死亡时淡出" 126 | 127 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:128 128 | msgid "Performance issues on edge cases" 129 | msgstr "边缘情况的性能问题" 130 | 131 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:131 132 | msgid "gtk4/glib/libadwaita stack upgrade" 133 | msgstr "升级 gtk4/glib/libadwaita 堆栈" 134 | 135 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:139 136 | msgid "Translations:" 137 | msgstr "翻译:" 138 | 139 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:141 140 | msgid "Add french translation (Rene Coty)" 141 | msgstr "添加法语翻译(Rene Coty)" 142 | 143 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:147 144 | msgid "This is a revision addressing a few problems" 145 | msgstr "这是一次修订,解决了几个问题" 146 | 147 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:149 148 | msgid "Fix interaction bugs" 149 | msgstr "修复交互错误" 150 | 151 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:150 152 | msgid "Minor performance tweaks" 153 | msgstr "轻微性能调整" 154 | 155 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:18 156 | msgid "Fades out cells when they die instead of deleting them in one go" 157 | msgstr "细胞死亡时会淡出,而不是一次性删除" 158 | 159 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:22 160 | msgid "" 161 | "The number of generations per seconds that should be computed when a " 162 | "simulation is running" 163 | msgstr "模拟运行时每秒应计算的代数" 164 | 165 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:32 166 | msgid "The width of the universe being generated, in cells number" 167 | msgstr "正在生成的宇宙宽度,以单细胞数表示" 168 | 169 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:36 170 | msgid "The height of the universe being generated, in cells number" 171 | msgstr "正在生成的宇宙宽度,以细胞数表示" 172 | 173 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:40 174 | msgid "Wheter to draw cells outline in universe grid" 175 | msgstr "是否在宇宙网格中绘制细胞轮廓" 176 | 177 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:44 178 | msgid "" 179 | "Wheter to allow universe rendering when the application window is resizing" 180 | msgstr "是否允许在调整应用程序窗口大小时进行宇宙渲染" 181 | 182 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:48 183 | msgid "Wheter to show an interaction hint on design mode activated" 184 | msgstr "是否在设计模式激活时显示交互提示" 185 | 186 | #: src/gtk/help-overlay.ui:11 187 | msgctxt "shortcut window" 188 | msgid "General" 189 | msgstr "常规" 190 | 191 | #: src/gtk/help-overlay.ui:14 192 | msgctxt "shortcut window" 193 | msgid "New Universe" 194 | msgstr "新建宇宙" 195 | 196 | #: src/gtk/help-overlay.ui:20 197 | msgctxt "shortcut window" 198 | msgid "Open Snapshot" 199 | msgstr "打开快照" 200 | 201 | #: src/gtk/help-overlay.ui:26 202 | msgctxt "shortcut window" 203 | msgid "Save Snapshot" 204 | msgstr "保存快照" 205 | 206 | #: src/gtk/help-overlay.ui:32 207 | msgctxt "shortcut window" 208 | msgid "Preferences" 209 | msgstr "首选项" 210 | 211 | #: src/gtk/help-overlay.ui:38 212 | msgctxt "shortcut window" 213 | msgid "Show Shortcuts" 214 | msgstr "显示快捷键" 215 | 216 | #: src/gtk/help-overlay.ui:44 217 | msgctxt "shortcut window" 218 | msgid "Close" 219 | msgstr "关闭" 220 | 221 | #: src/gtk/help-overlay.ui:52 222 | msgctxt "shortcut window" 223 | msgid "Universe Control" 224 | msgstr "宇宙控制" 225 | 226 | #: src/gtk/help-overlay.ui:55 227 | msgctxt "shortcut window" 228 | msgid "Toggle Design Mode" 229 | msgstr "切换设计模式" 230 | 231 | #: src/gtk/help-overlay.ui:61 232 | msgctxt "shortcut window" 233 | msgid "Toggle Run Universe" 234 | msgstr "切换运行宇宙" 235 | 236 | #: src/gtk/help-overlay.ui:67 237 | msgctxt "shortcut window" 238 | msgid "Seed Universe" 239 | msgstr "宇宙种子" 240 | 241 | #: src/window.rs:317 242 | msgid "Left click to make a cell alive, right click to make it dead" 243 | msgstr "左键单击可使细胞存活,右键单击可使其死亡" 244 | 245 | #: src/window.rs:320 246 | msgid "Do not show again" 247 | msgstr "不再显示" 248 | 249 | #: src/window.rs:340 250 | msgid "_Save" 251 | msgstr "保存(_S)" 252 | 253 | #: src/window.rs:341 src/window.rs:399 254 | msgid "_Cancel" 255 | msgstr "取消(_C)" 256 | 257 | #: src/window.rs:343 258 | msgid "Save universe snapshot" 259 | msgstr "保存宇宙快照" 260 | 261 | #: src/window.rs:368 262 | msgid "Unable to write to file" 263 | msgstr "无法写入文件" 264 | 265 | #: src/window.rs:374 266 | msgid "Unable to serialize snapshot" 267 | msgstr "无法序列化快照" 268 | 269 | #: src/window.rs:398 270 | msgid "_Open" 271 | msgstr "打开(_O)" 272 | 273 | #: src/window.rs:401 274 | msgid "Open universe snapshot" 275 | msgstr "打开宇宙快照" 276 | 277 | #: src/window.rs:430 src/window.rs:436 278 | msgid "Unreadable file" 279 | msgstr "无法读取的文件" 280 | 281 | #: src/window.rs:441 282 | msgid "File not existing or not accessible" 283 | msgstr "文件不存在或无法访问" 284 | 285 | #: src/window.rs:483 286 | msgid "Bad template data" 287 | msgstr "错误的模板数据" 288 | 289 | #: src/window.rs:489 290 | msgid "Template not found" 291 | msgstr "未发现模板" 292 | 293 | #: src/widgets/universe_controls.ui:53 294 | msgctxt "a11y" 295 | msgid "Toggle design mode" 296 | msgstr "切换设计模式" 297 | 298 | #: src/widgets/universe_controls.ui:62 299 | msgid "Toggle design tools" 300 | msgstr "切换设计工具" 301 | 302 | #: src/widgets/universe_controls.ui:74 303 | msgid "Cell brush" 304 | msgstr "细胞刷子" 305 | 306 | #: src/widgets/universe_controls.ui:80 307 | msgctxt "a11y" 308 | msgid "Cell brush" 309 | msgstr "细胞刷子" 310 | 311 | #: src/widgets/universe_controls.ui:87 312 | msgid "Randomly seed this universe" 313 | msgstr "为这个宇宙随机播种" 314 | 315 | #: src/widgets/universe_controls.ui:97 316 | msgctxt "a11y" 317 | msgid "Randomly seed this universe" 318 | msgstr "为这个宇宙随机播种" 319 | 320 | #: src/widgets/universe_controls.ui:110 321 | msgid "Toggle universe run" 322 | msgstr "切换宇宙运行" 323 | 324 | #: src/widgets/universe_controls.ui:118 325 | msgctxt "a11y" 326 | msgid "Toggle universe run" 327 | msgstr "切换宇宙运行" 328 | 329 | #: src/widgets/universe_controls.ui:125 330 | msgid "Skip forward one generation" 331 | msgstr "跳过一代" 332 | 333 | #: src/widgets/universe_controls.ui:135 334 | msgctxt "a11y" 335 | msgid "Skip forward one generation" 336 | msgstr "跳过一代" 337 | 338 | #: src/widgets/universe_controls.ui:169 339 | msgid "_New Universe" 340 | msgstr "新建宇宙(_N)" 341 | 342 | #: src/widgets/universe_controls.ui:173 343 | msgid "_Open Snapshot" 344 | msgstr "打开快照(_O)" 345 | 346 | #: src/widgets/universe_controls.ui:177 347 | msgid "_Save Snapshot" 348 | msgstr "保存快照(_S)" 349 | 350 | #: src/widgets/universe_controls.ui:183 351 | msgid "_Preferences" 352 | msgstr "首选项(_P)" 353 | 354 | #: src/widgets/universe_controls.ui:187 355 | msgid "_Keyboard Shortcuts" 356 | msgstr "键盘快捷键(_K)" 357 | 358 | #: src/widgets/universe_controls.ui:191 359 | msgid "_About Game of Life" 360 | msgstr "关于生命游戏(_A)" 361 | 362 | #: src/widgets/universe_controls.ui:195 363 | msgid "_Close" 364 | msgstr "关闭(_C)" 365 | 366 | #: src/widgets/new_universe_view.ui:4 367 | msgid "New universe" 368 | msgstr "新建宇宙" 369 | 370 | #: src/widgets/new_universe_view.ui:36 371 | msgid "Empty universe" 372 | msgstr "空宇宙" 373 | 374 | #: src/widgets/new_universe_view.ui:42 375 | msgid "Random seed" 376 | msgstr "随机种子" 377 | 378 | #: src/widgets/new_universe_view.ui:53 379 | msgid "Template" 380 | msgstr "模板" 381 | 382 | #: src/widgets/new_universe_view.ui:64 383 | msgid "Glider" 384 | msgstr "滑翔机" 385 | 386 | #: src/widgets/new_universe_view.ui:65 387 | msgid "Pulsar" 388 | msgstr "脉冲星" 389 | 390 | #: src/widgets/new_universe_view.ui:66 391 | msgid "Quadpole" 392 | msgstr "四极杆" 393 | 394 | #: src/widgets/new_universe_view.ui:67 395 | msgid "Spaceship" 396 | msgstr "宇宙飞船" 397 | 398 | #: src/widgets/new_universe_view.ui:68 399 | msgid "Circle of fire" 400 | msgstr "火焰之环" 401 | 402 | #: src/widgets/new_universe_view.ui:80 403 | msgid "Cancel" 404 | msgstr "取消" 405 | 406 | #: src/widgets/new_universe_view.ui:89 407 | msgid "Create" 408 | msgstr "创建" 409 | 410 | #: src/widgets/preferences_window.ui:6 411 | msgid "General" 412 | msgstr "常规" 413 | 414 | #: src/widgets/preferences_window.ui:10 415 | msgid "Feedbacks" 416 | msgstr "意见反馈" 417 | 418 | #: src/widgets/preferences_window.ui:11 419 | msgid "Various application feedbacks settings" 420 | msgstr "各种应用反馈设置" 421 | 422 | #: src/widgets/preferences_window.ui:14 423 | msgid "Design hint" 424 | msgstr "设计提示" 425 | 426 | #: src/widgets/preferences_window.ui:16 427 | msgid "Show a toast describing interaction modes during design mode" 428 | msgstr "在设计模式中显示描述交互模式的祝酒辞" 429 | 430 | #: src/widgets/preferences_window.ui:32 431 | msgid "Universe" 432 | msgstr "宇宙" 433 | 434 | #: src/widgets/preferences_window.ui:36 435 | msgid "Appearance" 436 | msgstr "外观" 437 | 438 | #: src/widgets/preferences_window.ui:39 439 | msgid "Light colors" 440 | msgstr "浅色" 441 | 442 | #: src/widgets/preferences_window.ui:40 443 | msgid "" 444 | "These colors are applied if you use a light scheme color on your desktop" 445 | msgstr "如果在桌面上使用浅色方案,就会应用这些颜色" 446 | 447 | #: src/widgets/preferences_window.ui:64 448 | msgid "Dark colors" 449 | msgstr "暗色" 450 | 451 | #: src/widgets/preferences_window.ui:65 452 | msgid "These colors are applied if you use a dark scheme color on your desktop" 453 | msgstr "如果在桌面上使用深色方案,则会应用这些颜色" 454 | 455 | #: src/widgets/preferences_window.ui:89 456 | msgid "Draw cells outline" 457 | msgstr "绘制细胞大纲" 458 | 459 | #: src/widgets/preferences_window.ui:102 460 | msgid "Fade out dead cells" 461 | msgstr "淡化死细胞" 462 | 463 | #: src/widgets/preferences_window.ui:115 464 | msgid "Render on resize" 465 | msgstr "调整尺寸时渲染" 466 | 467 | #: src/widgets/preferences_window.ui:118 468 | msgid "" 469 | "Allows rendering the grid during a resize event of the application window. " 470 | "May affect performance." 471 | msgstr "允许在应用程序窗口调整大小时渲染网格。可能会影响性能。" 472 | 473 | #: src/widgets/preferences_window.ui:133 474 | msgid "Evolution" 475 | msgstr "进化" 476 | 477 | #: src/widgets/preferences_window.ui:136 478 | msgid "Evolutions speed" 479 | msgstr "进化速度" 480 | 481 | #: src/widgets/preferences_window.ui:138 482 | msgid "The number of generations to be computed per second during an evolution" 483 | msgstr "进化过程中每秒计算的代数" 484 | -------------------------------------------------------------------------------- /po/en.po: -------------------------------------------------------------------------------- 1 | # English translations for game-of-life package. 2 | # Copyright (C) 2022 THE game-of-life'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the game-of-life package. 4 | # Automatically generated, 2022. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: game-of-life\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2023-03-03 15:13+0100\n" 11 | "PO-Revision-Date: 2022-09-20 00:48+0200\n" 12 | "Last-Translator: Automatically generated\n" 13 | "Language-Team: none\n" 14 | "Language: en\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 19 | 20 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:3 21 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:6 22 | msgid "Game of Life" 23 | msgstr "Game of Life" 24 | 25 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:4 26 | msgid "Game of Life Simulator" 27 | msgstr "Game of Life Simulator" 28 | 29 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:12 30 | msgid "simulation;game;" 31 | msgstr "" 32 | 33 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:7 34 | #, fuzzy 35 | msgid "Play Conway's Game of Life" 36 | msgstr "A simulator of Conway's game of life" 37 | 38 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:9 39 | msgid "" 40 | "Game of Life lets you simulate simple universes made of cells that can be " 41 | "alive or dead, and evolve according to simple rules." 42 | msgstr "" 43 | 44 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:13 45 | msgid "Current features:" 46 | msgstr "" 47 | 48 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:17 49 | #, fuzzy 50 | msgid "Random seed universes" 51 | msgstr "Randomly seed this universe" 52 | 53 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:18 54 | msgid "Provide start templates" 55 | msgstr "" 56 | 57 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:19 58 | #, fuzzy 59 | msgid "Manually edit universes" 60 | msgstr "Randomly seed this universe" 61 | 62 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:20 63 | #, fuzzy 64 | msgid "Save and restore snapshots" 65 | msgstr "Save the current state snapshot" 66 | 67 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:39 68 | msgid "Andrea Coronese" 69 | msgstr "Andrea Coronese" 70 | 71 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:55 72 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:68 73 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:81 74 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:94 75 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:110 76 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:123 77 | msgid "This release addresses the followings:" 78 | msgstr "" 79 | 80 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:57 81 | msgid "More consistent UI" 82 | msgstr "" 83 | 84 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:60 85 | msgid "Dutch translations (thanks Philip Goto)" 86 | msgstr "" 87 | 88 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:70 89 | msgid "Feature: step forward one generation" 90 | msgstr "" 91 | 92 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:73 93 | msgid "Group design tools in revealer" 94 | msgstr "" 95 | 96 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:83 97 | msgid "New icon (thanks to Tobias Bernard)" 98 | msgstr "" 99 | 100 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:86 101 | msgid "Reduce close button size" 102 | msgstr "" 103 | 104 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:96 105 | msgid "Fixes main menu button shape" 106 | msgstr "" 107 | 108 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:99 109 | msgid "Fixes a few problems with the main menu entries" 110 | msgstr "" 111 | 112 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:103 113 | msgid "Layout changes" 114 | msgstr "" 115 | 116 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:112 117 | msgid "Fixes templates not being loaded" 118 | msgstr "" 119 | 120 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:115 121 | msgid "Moves grid rendering to gtk4 render node api" 122 | msgstr "" 123 | 124 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:125 125 | msgid "Allow for cells fade out when they die" 126 | msgstr "" 127 | 128 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:128 129 | msgid "Performance issues on edge cases" 130 | msgstr "" 131 | 132 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:131 133 | msgid "gtk4/glib/libadwaita stack upgrade" 134 | msgstr "" 135 | 136 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:139 137 | msgid "Translations:" 138 | msgstr "" 139 | 140 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:141 141 | msgid "Add french translation (Rene Coty)" 142 | msgstr "" 143 | 144 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:147 145 | msgid "This is a revision addressing a few problems" 146 | msgstr "" 147 | 148 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:149 149 | msgid "Fix interaction bugs" 150 | msgstr "" 151 | 152 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:150 153 | msgid "Minor performance tweaks" 154 | msgstr "" 155 | 156 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:18 157 | msgid "Fades out cells when they die instead of deleting them in one go" 158 | msgstr "" 159 | 160 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:22 161 | msgid "" 162 | "The number of generations per seconds that should be computed when a " 163 | "simulation is running" 164 | msgstr "" 165 | "The number of generations per seconds that should be computed when a " 166 | "simulation is running" 167 | 168 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:32 169 | msgid "The width of the universe being generated, in cells number" 170 | msgstr "The width of the universe being generated, in cells number" 171 | 172 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:36 173 | msgid "The height of the universe being generated, in cells number" 174 | msgstr "The height of the universe being generated, in cells number" 175 | 176 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:40 177 | msgid "Wheter to draw cells outline in universe grid" 178 | msgstr "" 179 | 180 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:44 181 | msgid "" 182 | "Wheter to allow universe rendering when the application window is resizing" 183 | msgstr "" 184 | 185 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:48 186 | msgid "Wheter to show an interaction hint on design mode activated" 187 | msgstr "" 188 | 189 | #: src/gtk/help-overlay.ui:11 190 | msgctxt "shortcut window" 191 | msgid "General" 192 | msgstr "" 193 | 194 | #: src/gtk/help-overlay.ui:14 195 | #, fuzzy 196 | msgctxt "shortcut window" 197 | msgid "New Universe" 198 | msgstr "Toggle universe run" 199 | 200 | #: src/gtk/help-overlay.ui:20 201 | #, fuzzy 202 | msgctxt "shortcut window" 203 | msgid "Open Snapshot" 204 | msgstr "Save the current state snapshot" 205 | 206 | #: src/gtk/help-overlay.ui:26 207 | #, fuzzy 208 | msgctxt "shortcut window" 209 | msgid "Save Snapshot" 210 | msgstr "Save the current state snapshot" 211 | 212 | #: src/gtk/help-overlay.ui:32 213 | #, fuzzy 214 | msgctxt "shortcut window" 215 | msgid "Preferences" 216 | msgstr "_Preferences" 217 | 218 | #: src/gtk/help-overlay.ui:38 219 | #, fuzzy 220 | msgctxt "shortcut window" 221 | msgid "Show Shortcuts" 222 | msgstr "_Keyboard Shortcuts" 223 | 224 | #: src/gtk/help-overlay.ui:44 225 | msgctxt "shortcut window" 226 | msgid "Close" 227 | msgstr "" 228 | 229 | #: src/gtk/help-overlay.ui:52 230 | #, fuzzy 231 | msgctxt "shortcut window" 232 | msgid "Universe Control" 233 | msgstr "Universe evolution speed" 234 | 235 | #: src/gtk/help-overlay.ui:55 236 | #, fuzzy 237 | msgctxt "shortcut window" 238 | msgid "Toggle Design Mode" 239 | msgstr "Toggle design mode" 240 | 241 | #: src/gtk/help-overlay.ui:61 242 | #, fuzzy 243 | msgctxt "shortcut window" 244 | msgid "Toggle Run Universe" 245 | msgstr "Toggle universe run" 246 | 247 | #: src/gtk/help-overlay.ui:67 248 | #, fuzzy 249 | msgctxt "shortcut window" 250 | msgid "Seed Universe" 251 | msgstr "Toggle universe run" 252 | 253 | #: src/window.rs:317 254 | msgid "Left click to make a cell alive, right click to make it dead" 255 | msgstr "" 256 | 257 | #: src/window.rs:320 258 | msgid "Do not show again" 259 | msgstr "" 260 | 261 | #: src/window.rs:340 262 | msgid "_Save" 263 | msgstr "" 264 | 265 | #: src/window.rs:341 src/window.rs:399 266 | msgid "_Cancel" 267 | msgstr "" 268 | 269 | #: src/window.rs:343 270 | #, fuzzy 271 | msgid "Save universe snapshot" 272 | msgstr "Save the current state snapshot" 273 | 274 | #: src/window.rs:368 275 | msgid "Unable to write to file" 276 | msgstr "" 277 | 278 | #: src/window.rs:374 279 | msgid "Unable to serialize snapshot" 280 | msgstr "" 281 | 282 | #: src/window.rs:398 283 | msgid "_Open" 284 | msgstr "" 285 | 286 | #: src/window.rs:401 287 | msgid "Open universe snapshot" 288 | msgstr "" 289 | 290 | #: src/window.rs:430 src/window.rs:436 291 | msgid "Unreadable file" 292 | msgstr "" 293 | 294 | #: src/window.rs:441 295 | msgid "File not existing or not accessible" 296 | msgstr "" 297 | 298 | #: src/window.rs:483 299 | msgid "Bad template data" 300 | msgstr "" 301 | 302 | #: src/window.rs:489 303 | msgid "Template not found" 304 | msgstr "" 305 | 306 | #: src/widgets/universe_controls.ui:53 307 | msgctxt "a11y" 308 | msgid "Toggle design mode" 309 | msgstr "Toggle design mode" 310 | 311 | #: src/widgets/universe_controls.ui:62 312 | #, fuzzy 313 | msgid "Toggle design tools" 314 | msgstr "Toggle design mode" 315 | 316 | #: src/widgets/universe_controls.ui:74 317 | msgid "Cell brush" 318 | msgstr "" 319 | 320 | #: src/widgets/universe_controls.ui:80 321 | msgctxt "a11y" 322 | msgid "Cell brush" 323 | msgstr "" 324 | 325 | #: src/widgets/universe_controls.ui:87 326 | msgid "Randomly seed this universe" 327 | msgstr "Randomly seed this universe" 328 | 329 | #: src/widgets/universe_controls.ui:97 330 | msgctxt "a11y" 331 | msgid "Randomly seed this universe" 332 | msgstr "Randomly seed this universe" 333 | 334 | #: src/widgets/universe_controls.ui:110 335 | msgid "Toggle universe run" 336 | msgstr "Toggle universe run" 337 | 338 | #: src/widgets/universe_controls.ui:118 339 | msgctxt "a11y" 340 | msgid "Toggle universe run" 341 | msgstr "Toggle universe run" 342 | 343 | #: src/widgets/universe_controls.ui:125 344 | msgid "Skip forward one generation" 345 | msgstr "" 346 | 347 | #: src/widgets/universe_controls.ui:135 348 | msgctxt "a11y" 349 | msgid "Skip forward one generation" 350 | msgstr "" 351 | 352 | #: src/widgets/universe_controls.ui:169 353 | #, fuzzy 354 | msgid "_New Universe" 355 | msgstr "Toggle universe run" 356 | 357 | #: src/widgets/universe_controls.ui:173 358 | msgid "_Open Snapshot" 359 | msgstr "" 360 | 361 | #: src/widgets/universe_controls.ui:177 362 | #, fuzzy 363 | msgid "_Save Snapshot" 364 | msgstr "Save the current state snapshot" 365 | 366 | #: src/widgets/universe_controls.ui:183 367 | msgid "_Preferences" 368 | msgstr "_Preferences" 369 | 370 | #: src/widgets/universe_controls.ui:187 371 | msgid "_Keyboard Shortcuts" 372 | msgstr "_Keyboard Shortcuts" 373 | 374 | #: src/widgets/universe_controls.ui:191 375 | #, fuzzy 376 | msgid "_About Game of Life" 377 | msgstr "_About Game of Life" 378 | 379 | #: src/widgets/universe_controls.ui:195 380 | msgid "_Close" 381 | msgstr "" 382 | 383 | #: src/widgets/new_universe_view.ui:4 384 | #, fuzzy 385 | msgid "New universe" 386 | msgstr "Toggle universe run" 387 | 388 | #: src/widgets/new_universe_view.ui:36 389 | msgid "Empty universe" 390 | msgstr "" 391 | 392 | #: src/widgets/new_universe_view.ui:42 393 | msgid "Random seed" 394 | msgstr "" 395 | 396 | #: src/widgets/new_universe_view.ui:53 397 | msgid "Template" 398 | msgstr "" 399 | 400 | #: src/widgets/new_universe_view.ui:64 401 | msgid "Glider" 402 | msgstr "" 403 | 404 | #: src/widgets/new_universe_view.ui:65 405 | msgid "Pulsar" 406 | msgstr "" 407 | 408 | #: src/widgets/new_universe_view.ui:66 409 | msgid "Quadpole" 410 | msgstr "" 411 | 412 | #: src/widgets/new_universe_view.ui:67 413 | msgid "Spaceship" 414 | msgstr "" 415 | 416 | #: src/widgets/new_universe_view.ui:68 417 | msgid "Circle of fire" 418 | msgstr "" 419 | 420 | #: src/widgets/new_universe_view.ui:80 421 | msgid "Cancel" 422 | msgstr "" 423 | 424 | #: src/widgets/new_universe_view.ui:89 425 | msgid "Create" 426 | msgstr "" 427 | 428 | #: src/widgets/preferences_window.ui:6 429 | msgid "General" 430 | msgstr "" 431 | 432 | #: src/widgets/preferences_window.ui:10 433 | msgid "Feedbacks" 434 | msgstr "" 435 | 436 | #: src/widgets/preferences_window.ui:11 437 | msgid "Various application feedbacks settings" 438 | msgstr "" 439 | 440 | #: src/widgets/preferences_window.ui:14 441 | msgid "Design hint" 442 | msgstr "" 443 | 444 | #: src/widgets/preferences_window.ui:16 445 | msgid "Show a toast describing interaction modes during design mode" 446 | msgstr "" 447 | 448 | #: src/widgets/preferences_window.ui:32 449 | msgid "Universe" 450 | msgstr "" 451 | 452 | #: src/widgets/preferences_window.ui:36 453 | msgid "Appearance" 454 | msgstr "" 455 | 456 | #: src/widgets/preferences_window.ui:39 457 | msgid "Light colors" 458 | msgstr "" 459 | 460 | #: src/widgets/preferences_window.ui:40 461 | msgid "" 462 | "These colors are applied if you use a light scheme color on your desktop" 463 | msgstr "" 464 | 465 | #: src/widgets/preferences_window.ui:64 466 | msgid "Dark colors" 467 | msgstr "" 468 | 469 | #: src/widgets/preferences_window.ui:65 470 | msgid "These colors are applied if you use a dark scheme color on your desktop" 471 | msgstr "" 472 | 473 | #: src/widgets/preferences_window.ui:89 474 | msgid "Draw cells outline" 475 | msgstr "" 476 | 477 | #: src/widgets/preferences_window.ui:102 478 | msgid "Fade out dead cells" 479 | msgstr "" 480 | 481 | #: src/widgets/preferences_window.ui:115 482 | msgid "Render on resize" 483 | msgstr "" 484 | 485 | #: src/widgets/preferences_window.ui:118 486 | msgid "" 487 | "Allows rendering the grid during a resize event of the application window. " 488 | "May affect performance." 489 | msgstr "" 490 | 491 | #: src/widgets/preferences_window.ui:133 492 | msgid "Evolution" 493 | msgstr "" 494 | 495 | #: src/widgets/preferences_window.ui:136 496 | #, fuzzy 497 | msgid "Evolutions speed" 498 | msgstr "Universe evolution speed" 499 | 500 | #: src/widgets/preferences_window.ui:138 501 | #, fuzzy 502 | msgid "The number of generations to be computed per second during an evolution" 503 | msgstr "" 504 | "The number of generations per seconds that should be computed when a " 505 | "simulation is running" 506 | 507 | #~ msgid "Save the current state snapshot" 508 | #~ msgstr "Save the current state snapshot" 509 | 510 | #~ msgctxt "a11y" 511 | #~ msgid "Save the current state snapshot" 512 | #~ msgstr "Save the current state snapshot" 513 | 514 | #, fuzzy 515 | #~ msgctxt "shortcut window" 516 | #~ msgid "New universe" 517 | #~ msgstr "Toggle universe run" 518 | 519 | #~ msgid "_About game-of-life" 520 | #~ msgstr "_About game-of-life" 521 | 522 | #~ msgctxt "a11y" 523 | #~ msgid "Modify universe evolution speed" 524 | #~ msgstr "Modify universe evolution speed" 525 | -------------------------------------------------------------------------------- /src/models/universe.rs: -------------------------------------------------------------------------------- 1 | use super::{UniverseCell, UniversePoint, UniversePointMatrix}; 2 | use crate::config::G_LOG_DOMAIN; 3 | use rand::Rng; 4 | use serde::{Deserialize, Serialize}; 5 | use std::fmt; 6 | 7 | const UNIVERSE_RANDOM_ALIVE_PROBABILITY: f64 = 0.6; 8 | const UNIVERSE_CELL_INITIAL_CORPSE_HEAT: f64 = 0.65; 9 | const UNIVERSE_DEFAULT_FREEZE_RATE: f64 = 0.30; 10 | 11 | fn compute_initial_delta(universe: &mut Universe) { 12 | let mut initial_delta: Vec = vec![]; 13 | for row in 0..universe.rows { 14 | for column in 0..universe.columns { 15 | let index = universe.get_index(row, column); 16 | let delta_point = UniversePoint::new( 17 | row, 18 | column, 19 | universe.cells[index], 20 | universe.death_map[index], 21 | ); 22 | initial_delta.push(delta_point); 23 | } 24 | } 25 | 26 | universe.last_delta = Some(initial_delta); 27 | } 28 | 29 | /// Represents a universe as a collection of "cells" 30 | /// which can be in two states: `Alive` or `Dead` 31 | #[derive(Clone, Debug)] 32 | pub struct Universe { 33 | columns: usize, 34 | rows: usize, 35 | cells: Vec, 36 | death_map: Vec, 37 | corpse_freeze_rate: f64, 38 | generations: u64, 39 | last_delta: Option>, 40 | } 41 | 42 | impl Default for Universe { 43 | fn default() -> Self { 44 | Universe::new_random(200, 200) 45 | } 46 | } 47 | 48 | impl Universe { 49 | pub fn new(width: usize, height: usize) -> Universe { 50 | let mut universe = Self::create(width, height); 51 | compute_initial_delta(&mut universe); 52 | universe 53 | } 54 | 55 | pub fn new_random(rows: usize, columns: usize) -> Universe { 56 | let mut universe = Self::create(rows, columns); 57 | universe.random_seed(); 58 | compute_initial_delta(&mut universe); 59 | universe 60 | } 61 | 62 | pub fn new_empty(rows: usize, columns: usize) -> Universe { 63 | Self::create(rows, columns) 64 | } 65 | 66 | fn create(rows: usize, columns: usize) -> Universe { 67 | let s: usize = rows * columns; 68 | let mut cells: Vec = Vec::with_capacity(s); 69 | let mut death_map: Vec = Vec::with_capacity(s); 70 | 71 | for i in 0..s { 72 | cells.insert(i, UniverseCell::Dead); 73 | death_map.insert(i, 0.0); 74 | } 75 | 76 | Universe { 77 | rows, 78 | columns, 79 | cells, 80 | corpse_freeze_rate: UNIVERSE_DEFAULT_FREEZE_RATE, 81 | death_map, 82 | generations: 0, 83 | last_delta: None, 84 | } 85 | } 86 | 87 | /// Seeds this universe with random values 88 | fn random_seed(&mut self) { 89 | let mut rng = rand::thread_rng(); 90 | for i in 0..self.rows { 91 | for j in 0..self.columns { 92 | let y: f64 = rng.gen(); 93 | if y >= UNIVERSE_RANDOM_ALIVE_PROBABILITY { 94 | self.set_cell(i, j, UniverseCell::Alive); 95 | } else { 96 | self.set_cell(i, j, UniverseCell::Dead); 97 | } 98 | } 99 | } 100 | } 101 | 102 | #[allow(dead_code)] 103 | fn clear_delta(&mut self) { 104 | self.last_delta = None; 105 | } 106 | 107 | fn get_index(&self, row: usize, column: usize) -> usize { 108 | (row * self.columns) + column 109 | } 110 | 111 | /// Sets cell at `row`x`column` coordinates 112 | pub fn set_cell(&mut self, row: usize, column: usize, cell: UniverseCell) { 113 | let i = self.get_index(row, column); 114 | self.cells[i] = cell; 115 | } 116 | 117 | /// Gets the cell at `row`x`column`. 118 | /// # Panics 119 | /// Panics if no cell is found 120 | pub fn get_cell(&self, row: usize, column: usize) -> (&UniverseCell, &f64) { 121 | let idx = self.get_index(row, column); 122 | match self.cells.get(idx) { 123 | Some(cell) => (cell, self.death_map.get(idx).unwrap_or(&0.0)), 124 | None => panic!("Could not get cell at row {row} column {column}"), 125 | } 126 | } 127 | 128 | /// Computes the next state of a cell given its current state 129 | /// and the state of its neighbours 130 | fn cell_next_state(&self, row: usize, column: usize) -> UniverseCell { 131 | let (cell, _) = self.get_cell(row, column); 132 | let alive_cells_around = self.cell_living_neighbours_count(row, column); 133 | 134 | match cell { 135 | UniverseCell::Alive => { 136 | if !(2..=3).contains(&alive_cells_around) { 137 | UniverseCell::Dead 138 | } else { 139 | // This include the condition alive_cells_around == 2 || alive_cells_around == 3 140 | UniverseCell::Alive 141 | } 142 | } 143 | 144 | UniverseCell::Dead => { 145 | if alive_cells_around == 3 { 146 | UniverseCell::Alive 147 | } else { 148 | UniverseCell::Dead 149 | } 150 | } 151 | } 152 | } 153 | 154 | /// Counts living adiacents cells for a given cell at `row`x`column` coordinates 155 | fn cell_living_neighbours_count(&self, row: usize, column: usize) -> u8 { 156 | let mut count = 0; 157 | let rows = [self.rows - 1, 0, 1]; 158 | let cols = [self.columns - 1, 0, 1]; 159 | for delta_row in rows.iter() { 160 | for delta_col in cols.iter() { 161 | if *delta_row == 0 && *delta_col == 0 { 162 | continue; 163 | } 164 | 165 | let neighbor_row = (row + delta_row) % self.rows; 166 | let neighbor_col = (column + delta_col) % self.columns; 167 | let idx = self.get_index(neighbor_row, neighbor_col); 168 | match self.cells[idx] { 169 | UniverseCell::Alive => count += 1, 170 | UniverseCell::Dead => (), 171 | }; 172 | } 173 | } 174 | count 175 | } 176 | 177 | /// Iterates over this universe and computes its next generation. 178 | /// Alters the struct in-place. 179 | pub fn tick(&mut self) { 180 | let mut new_state = Self::new(self.columns, self.rows); 181 | 182 | let mut delta: Vec = Vec::with_capacity(self.cells.capacity()); 183 | for point in self.iter_cells() { 184 | let index = self.get_index(point.row(), point.column()); 185 | let cell_current_state = point.cell(); 186 | let cell_next_state = self.cell_next_state(point.row(), point.column()); 187 | let death_map_item_ref = new_state.death_map.get_mut(index).unwrap(); 188 | new_state.cells[index] = cell_next_state; 189 | 190 | if cell_next_state != *cell_current_state { 191 | match cell_next_state { 192 | UniverseCell::Alive => { 193 | // Cell becomes alive 194 | *death_map_item_ref = 0.0; 195 | } 196 | UniverseCell::Dead => { 197 | // Cell dies 198 | *death_map_item_ref = UNIVERSE_CELL_INITIAL_CORPSE_HEAT; 199 | } 200 | } 201 | delta.push(UniversePoint::new( 202 | point.row(), 203 | point.column(), 204 | cell_next_state, 205 | *death_map_item_ref, 206 | )); 207 | } else { 208 | // Dead cell corpse keeps freezing 209 | if *cell_current_state == UniverseCell::Dead && *death_map_item_ref > 0.0 { 210 | *death_map_item_ref = point.corpse_heat() - UNIVERSE_DEFAULT_FREEZE_RATE; 211 | } 212 | } 213 | } 214 | self.cells = new_state.cells.clone(); 215 | self.death_map = new_state.death_map.clone(); 216 | self.generations += 1; 217 | self.last_delta = Some(delta); 218 | } 219 | 220 | /// Counts and returns the number of alive cells 221 | /// in this universe 222 | pub fn alive_cells_count(&self) -> usize { 223 | self.cells 224 | .iter() 225 | .filter(|cell| match cell { 226 | UniverseCell::Alive => true, 227 | UniverseCell::Dead => false, 228 | }) 229 | .count() 230 | } 231 | 232 | /// Counts and returns the number of dead cells 233 | /// in this universe 234 | pub fn dead_cells_count(&self) -> usize { 235 | self.cells 236 | .iter() 237 | .filter(|cell| match cell { 238 | UniverseCell::Alive => false, 239 | UniverseCell::Dead => true, 240 | }) 241 | .count() 242 | } 243 | 244 | /// Gets the last delta for this universe. 245 | /// If no iterations have been performed, this will be a delta 246 | /// with the current values of all the universe itself 247 | pub fn last_delta(&self) -> Vec { 248 | match &self.last_delta { 249 | Some(delta) => delta.to_vec(), 250 | None => self.iter_cells().collect::>(), 251 | } 252 | } 253 | 254 | pub fn iter_cells(&self) -> UniverseIterator<'_> { 255 | UniverseIterator::new(self) 256 | } 257 | 258 | pub fn snapshot(&self) -> UniverseSnapshot { 259 | UniverseSnapshot::from(self) 260 | } 261 | 262 | pub fn corpse_freeze_rate(&self) -> &f64 { 263 | &self.corpse_freeze_rate 264 | } 265 | 266 | pub fn set_corpse_freeze_rate(&mut self, value: f64) { 267 | self.corpse_freeze_rate = value; 268 | } 269 | } 270 | 271 | impl UniversePointMatrix for Universe { 272 | type SetCellError = (); 273 | 274 | fn rows(&self) -> usize { 275 | self.rows 276 | } 277 | 278 | fn columns(&self) -> usize { 279 | self.columns 280 | } 281 | 282 | fn get(&self, row: usize, column: usize) -> Option { 283 | let idx = self.get_index(row, column); 284 | self.cells.get(idx).map(|cell| { 285 | UniversePoint::new(row, column, *cell, *self.death_map.get(idx).unwrap_or(&0.0)) 286 | }) 287 | } 288 | 289 | fn set( 290 | &mut self, 291 | row: usize, 292 | column: usize, 293 | value: UniverseCell, 294 | ) -> Result { 295 | self.set_cell(row, column, value); 296 | Ok(self.get(row, column).unwrap()) 297 | } 298 | } 299 | 300 | pub struct UniverseIterator<'a> { 301 | universe: &'a Universe, 302 | row: usize, 303 | column: usize, 304 | } 305 | 306 | impl<'a> UniverseIterator<'a> { 307 | pub fn new(universe: &'a Universe) -> Self { 308 | Self { 309 | universe, 310 | row: 0, 311 | column: 0, 312 | } 313 | } 314 | } 315 | 316 | impl<'a> Iterator for UniverseIterator<'a> { 317 | type Item = UniversePoint; 318 | 319 | fn next(&mut self) -> Option { 320 | if self.row == self.universe.rows() && self.column == self.universe.columns() { 321 | return None; 322 | } 323 | 324 | if self.row == self.universe.rows() - 1 && self.column == self.universe.columns() - 1 { 325 | // This is the last item. Return it and set counters to above the last item 326 | let (last, last_corpse_heath) = self.universe.get_cell(self.row, self.column); 327 | self.row += 1; 328 | self.column += 1; 329 | 330 | return Some(UniversePoint::new( 331 | self.row - 1, 332 | self.column - 1, 333 | *last, 334 | *last_corpse_heath, 335 | )); 336 | } 337 | 338 | let (cell, corpse_heat) = self.universe.get_cell(self.row, self.column); 339 | 340 | let point = UniversePoint::new(self.row, self.column, *cell, *corpse_heat); 341 | 342 | if self.column == self.universe.columns() - 1 { 343 | self.column = 0; 344 | self.row += 1; 345 | } else { 346 | self.column += 1; 347 | } 348 | 349 | Some(point) 350 | } 351 | } 352 | 353 | impl fmt::Display for Universe { 354 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 355 | for line in self.cells.as_slice().chunks(self.columns()) { 356 | for &cell in line { 357 | let symbol = if cell == UniverseCell::Dead { 358 | '◻' 359 | } else { 360 | '◼' 361 | }; 362 | write!(f, "{symbol}")?; 363 | } 364 | writeln!(f)?; 365 | } 366 | writeln!(f) 367 | } 368 | } 369 | 370 | impl Drop for Universe { 371 | fn drop(&mut self) { 372 | self.cells.clear(); 373 | self.generations = 0; 374 | } 375 | } 376 | 377 | #[derive(Serialize, Deserialize, Debug)] 378 | pub struct UniverseSnapshot { 379 | rows: usize, 380 | columns: usize, 381 | cells: Vec, 382 | 383 | #[serde(skip, default)] 384 | death_map: Vec, 385 | } 386 | 387 | impl From<&Universe> for UniverseSnapshot { 388 | fn from(value: &Universe) -> Self { 389 | UniverseSnapshot { 390 | cells: value.cells.clone(), 391 | death_map: value.death_map.clone(), 392 | rows: value.rows(), 393 | columns: value.columns(), 394 | } 395 | } 396 | } 397 | 398 | impl UniverseSnapshot { 399 | fn get_index(&self, row: usize, column: usize) -> usize { 400 | (row * self.columns) + column 401 | } 402 | 403 | pub fn serialize(&self) -> Result, bincode::Error> { 404 | bincode::serialize(self) 405 | } 406 | } 407 | 408 | impl UniversePointMatrix for UniverseSnapshot { 409 | type SetCellError = &'static str; 410 | 411 | fn rows(&self) -> usize { 412 | self.rows 413 | } 414 | 415 | fn columns(&self) -> usize { 416 | self.columns 417 | } 418 | 419 | fn get(&self, row: usize, column: usize) -> Option { 420 | let idx = self.get_index(row, column); 421 | self.cells 422 | .get(idx) 423 | .map(|cell| UniversePoint::new(row, column, *cell, self.death_map[idx])) 424 | } 425 | 426 | fn set( 427 | &mut self, 428 | _row: usize, 429 | _column: usize, 430 | _value: UniverseCell, 431 | ) -> Result { 432 | Err("UniverseSnapshot is readonly") 433 | } 434 | } 435 | 436 | #[derive(Debug)] 437 | pub enum SnapshotError { 438 | Invalid, 439 | } 440 | 441 | impl TryFrom<&Vec> for UniverseSnapshot { 442 | type Error = SnapshotError; 443 | fn try_from(value: &Vec) -> Result { 444 | match bincode::deserialize::(value.as_ref()) { 445 | Ok(snapshot) => Ok(snapshot), 446 | Err(error) => { 447 | glib::g_critical!(G_LOG_DOMAIN, "{}", error); 448 | Err(SnapshotError::Invalid) 449 | } 450 | } 451 | } 452 | } 453 | 454 | impl From for Universe { 455 | fn from(snapshot: UniverseSnapshot) -> Self { 456 | let mut death_map = Vec::with_capacity(snapshot.rows * snapshot.columns); 457 | death_map.fill(0.0); 458 | 459 | Self { 460 | rows: snapshot.rows, 461 | columns: snapshot.columns, 462 | corpse_freeze_rate: UNIVERSE_DEFAULT_FREEZE_RATE, 463 | death_map, 464 | cells: snapshot.cells, 465 | generations: 0, 466 | last_delta: None, 467 | } 468 | } 469 | } 470 | -------------------------------------------------------------------------------- /po/nl.po: -------------------------------------------------------------------------------- 1 | # Dutch translations for game-of-life package. 2 | # Copyright (C) 2023 THE game-of-life'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the game-of-life package. 4 | # Automatically generated, 2023. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: game-of-life\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2023-03-03 15:13+0100\n" 11 | "PO-Revision-Date: 2023-03-03 14:26+0100\n" 12 | "Last-Translator: Philip Goto \n" 13 | "Language-Team: none\n" 14 | "Language: nl\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 19 | "X-Generator: Poedit 3.1.1\n" 20 | 21 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:3 22 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:6 23 | msgid "Game of Life" 24 | msgstr "Game of Life" 25 | 26 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:4 27 | msgid "Game of Life Simulator" 28 | msgstr "Simulator voor de Game of Life" 29 | 30 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:12 31 | msgid "simulation;game;" 32 | msgstr "simulation;game;simulatie;spel;" 33 | 34 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:7 35 | msgid "Play Conway's Game of Life" 36 | msgstr "Speel Conway's Game of Life" 37 | 38 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:9 39 | msgid "" 40 | "Game of Life lets you simulate simple universes made of cells that can be " 41 | "alive or dead, and evolve according to simple rules." 42 | msgstr "" 43 | "Game of Life laat u eenvoudige universums simuleren, welke bestaan uit " 44 | "cellen die levend of dood kunnen zijn en evolueren volgens eenvoudige regels." 45 | 46 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:13 47 | msgid "Current features:" 48 | msgstr "Huidige functies:" 49 | 50 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:17 51 | msgid "Random seed universes" 52 | msgstr "Genereer willekeurige universa" 53 | 54 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:18 55 | msgid "Provide start templates" 56 | msgstr "Sjablonen om mee te beginnen" 57 | 58 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:19 59 | msgid "Manually edit universes" 60 | msgstr "Bewerk universums handmatig" 61 | 62 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:20 63 | msgid "Save and restore snapshots" 64 | msgstr "Sla momentopnamen op en herstel deze" 65 | 66 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:39 67 | msgid "Andrea Coronese" 68 | msgstr "Andrea Coronese" 69 | 70 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:55 71 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:68 72 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:81 73 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:94 74 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:110 75 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:123 76 | msgid "This release addresses the followings:" 77 | msgstr "Deze uitgave bevat de volgende wijzigingen:" 78 | 79 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:57 80 | msgid "More consistent UI" 81 | msgstr "" 82 | 83 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:60 84 | msgid "Dutch translations (thanks Philip Goto)" 85 | msgstr "" 86 | 87 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:70 88 | msgid "Feature: step forward one generation" 89 | msgstr "Functie: stap één generatie vooruit" 90 | 91 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:73 92 | msgid "Group design tools in revealer" 93 | msgstr "Ontwerpgereedschap gegroepeerd" 94 | 95 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:83 96 | msgid "New icon (thanks to Tobias Bernard)" 97 | msgstr "Nieuw pictogram (door Tobias Bernard)" 98 | 99 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:86 100 | msgid "Reduce close button size" 101 | msgstr "Sluitknop verkleind" 102 | 103 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:96 104 | msgid "Fixes main menu button shape" 105 | msgstr "Vorm van hoofdmenuknop verbeterd" 106 | 107 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:99 108 | msgid "Fixes a few problems with the main menu entries" 109 | msgstr "Enkele problemen opgelost met de items in het hoofdmenu" 110 | 111 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:103 112 | msgid "Layout changes" 113 | msgstr "Wijzigingen in de lay-out" 114 | 115 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:112 116 | msgid "Fixes templates not being loaded" 117 | msgstr "Verhelpt sjablonen die niet worden geladen" 118 | 119 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:115 120 | msgid "Moves grid rendering to gtk4 render node api" 121 | msgstr "Raster-rendering naar de render-node-API van GTK 4 omgeschreven" 122 | 123 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:125 124 | msgid "Allow for cells fade out when they die" 125 | msgstr "Sta toe dat cellen vervagen als ze sterven" 126 | 127 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:128 128 | msgid "Performance issues on edge cases" 129 | msgstr "Enkele prestatieproblemen verholpen" 130 | 131 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:131 132 | msgid "gtk4/glib/libadwaita stack upgrade" 133 | msgstr "Stack-upgrade van GTK 4/GLib/LibAdwaita" 134 | 135 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:139 136 | msgid "Translations:" 137 | msgstr "Vertalingen:" 138 | 139 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:141 140 | msgid "Add french translation (Rene Coty)" 141 | msgstr "Franse vertaling toegevoegd (door René Coty)" 142 | 143 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:147 144 | msgid "This is a revision addressing a few problems" 145 | msgstr "Dit is een herziening welke enkele problemen aanpakt" 146 | 147 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:149 148 | msgid "Fix interaction bugs" 149 | msgstr "Interactiefouten opgelost" 150 | 151 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:150 152 | msgid "Minor performance tweaks" 153 | msgstr "Kleine prestatie-aanpassingen" 154 | 155 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:18 156 | msgid "Fades out cells when they die instead of deleting them in one go" 157 | msgstr "" 158 | "Vervaagt cellen wanneer ze sterven in plaats van ze in één keer te " 159 | "verwijderen" 160 | 161 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:22 162 | msgid "" 163 | "The number of generations per seconds that should be computed when a " 164 | "simulation is running" 165 | msgstr "" 166 | "Het aantal generaties per seconde dat moet worden berekend wanneer een " 167 | "simulatie loopt" 168 | 169 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:32 170 | msgid "The width of the universe being generated, in cells number" 171 | msgstr "De breedte van het gegenereerde universum, in cellenaantal" 172 | 173 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:36 174 | msgid "The height of the universe being generated, in cells number" 175 | msgstr "De hoogte van het gegenereerde universum, in cellenaantal" 176 | 177 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:40 178 | msgid "Wheter to draw cells outline in universe grid" 179 | msgstr "Of de omtrek van de cellen in het universumraster moet worden getekend" 180 | 181 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:44 182 | msgid "" 183 | "Wheter to allow universe rendering when the application window is resizing" 184 | msgstr "" 185 | "Of het universum mag worden getekend wanneer de grootte van het app-venster " 186 | "wordt aangepast" 187 | 188 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:48 189 | msgid "Wheter to show an interaction hint on design mode activated" 190 | msgstr "" 191 | "Of er een interactiehint moet worden getoond wanneer ontwerpmodus wordt " 192 | "geactiveerd" 193 | 194 | #: src/gtk/help-overlay.ui:11 195 | msgctxt "shortcut window" 196 | msgid "General" 197 | msgstr "Algemeen" 198 | 199 | #: src/gtk/help-overlay.ui:14 200 | msgctxt "shortcut window" 201 | msgid "New Universe" 202 | msgstr "Nieuw universum" 203 | 204 | #: src/gtk/help-overlay.ui:20 205 | msgctxt "shortcut window" 206 | msgid "Open Snapshot" 207 | msgstr "Momentopname openen" 208 | 209 | #: src/gtk/help-overlay.ui:26 210 | msgctxt "shortcut window" 211 | msgid "Save Snapshot" 212 | msgstr "Momentopname opslaan" 213 | 214 | #: src/gtk/help-overlay.ui:32 215 | msgctxt "shortcut window" 216 | msgid "Preferences" 217 | msgstr "Voorkeuren" 218 | 219 | #: src/gtk/help-overlay.ui:38 220 | msgctxt "shortcut window" 221 | msgid "Show Shortcuts" 222 | msgstr "Sneltoetsen tonen" 223 | 224 | #: src/gtk/help-overlay.ui:44 225 | msgctxt "shortcut window" 226 | msgid "Close" 227 | msgstr "Sluiten" 228 | 229 | #: src/gtk/help-overlay.ui:52 230 | msgctxt "shortcut window" 231 | msgid "Universe Control" 232 | msgstr "Universumbeheer" 233 | 234 | #: src/gtk/help-overlay.ui:55 235 | msgctxt "shortcut window" 236 | msgid "Toggle Design Mode" 237 | msgstr "Ontwerpmodus omschakelen" 238 | 239 | #: src/gtk/help-overlay.ui:61 240 | msgctxt "shortcut window" 241 | msgid "Toggle Run Universe" 242 | msgstr "Universum uitvoeren/pauzeren" 243 | 244 | #: src/gtk/help-overlay.ui:67 245 | msgctxt "shortcut window" 246 | msgid "Seed Universe" 247 | msgstr "Willekeurig universum genereren" 248 | 249 | #: src/window.rs:317 250 | msgid "Left click to make a cell alive, right click to make it dead" 251 | msgstr "" 252 | "Linkermuisknop om een cel levend te maken, rechtermuisknop om deze dood te " 253 | "maken" 254 | 255 | #: src/window.rs:320 256 | msgid "Do not show again" 257 | msgstr "Toon dit niet opnieuw" 258 | 259 | #: src/window.rs:340 260 | msgid "_Save" 261 | msgstr "_Opslaan" 262 | 263 | #: src/window.rs:341 src/window.rs:399 264 | msgid "_Cancel" 265 | msgstr "_Annuleren" 266 | 267 | #: src/window.rs:343 268 | msgid "Save universe snapshot" 269 | msgstr "Momentopname van universum opslaan" 270 | 271 | #: src/window.rs:368 272 | msgid "Unable to write to file" 273 | msgstr "Kon niet naar bestand schrijven" 274 | 275 | #: src/window.rs:374 276 | msgid "Unable to serialize snapshot" 277 | msgstr "Kon momentopname niet serialiseren" 278 | 279 | #: src/window.rs:398 280 | msgid "_Open" 281 | msgstr "_Openen" 282 | 283 | #: src/window.rs:401 284 | msgid "Open universe snapshot" 285 | msgstr "Momentopname van universum openen" 286 | 287 | #: src/window.rs:430 src/window.rs:436 288 | msgid "Unreadable file" 289 | msgstr "Onleesbaar bestand" 290 | 291 | #: src/window.rs:441 292 | msgid "File not existing or not accessible" 293 | msgstr "Bestand bestaat niet of is niet toegankelijk" 294 | 295 | #: src/window.rs:483 296 | msgid "Bad template data" 297 | msgstr "Ongeldige sjabloongegevens" 298 | 299 | #: src/window.rs:489 300 | msgid "Template not found" 301 | msgstr "Sjabloon niet gevonden" 302 | 303 | #: src/widgets/universe_controls.ui:53 304 | msgctxt "a11y" 305 | msgid "Toggle design mode" 306 | msgstr "Ontwerpmodus omschakelen" 307 | 308 | #: src/widgets/universe_controls.ui:62 309 | msgid "Toggle design tools" 310 | msgstr "Ontwerpgereedschap omschakelen" 311 | 312 | #: src/widgets/universe_controls.ui:74 313 | msgid "Cell brush" 314 | msgstr "Celkwast" 315 | 316 | #: src/widgets/universe_controls.ui:80 317 | msgctxt "a11y" 318 | msgid "Cell brush" 319 | msgstr "Celkwast" 320 | 321 | #: src/widgets/universe_controls.ui:87 322 | msgid "Randomly seed this universe" 323 | msgstr "Willekeurig universum genereren" 324 | 325 | #: src/widgets/universe_controls.ui:97 326 | msgctxt "a11y" 327 | msgid "Randomly seed this universe" 328 | msgstr "Willekeurig universum genereren" 329 | 330 | #: src/widgets/universe_controls.ui:110 331 | msgid "Toggle universe run" 332 | msgstr "Universum uitvoeren/pauzeren" 333 | 334 | #: src/widgets/universe_controls.ui:118 335 | msgctxt "a11y" 336 | msgid "Toggle universe run" 337 | msgstr "Universum uitvoeren/pauzeren" 338 | 339 | #: src/widgets/universe_controls.ui:125 340 | msgid "Skip forward one generation" 341 | msgstr "Volgende generatie" 342 | 343 | #: src/widgets/universe_controls.ui:135 344 | msgctxt "a11y" 345 | msgid "Skip forward one generation" 346 | msgstr "Volgende generatie" 347 | 348 | #: src/widgets/universe_controls.ui:169 349 | msgid "_New Universe" 350 | msgstr "_Nieuw universum" 351 | 352 | #: src/widgets/universe_controls.ui:173 353 | msgid "_Open Snapshot" 354 | msgstr "Momentopname _openen" 355 | 356 | #: src/widgets/universe_controls.ui:177 357 | msgid "_Save Snapshot" 358 | msgstr "Momentopname op_slaan" 359 | 360 | #: src/widgets/universe_controls.ui:183 361 | msgid "_Preferences" 362 | msgstr "_Voorkeuren" 363 | 364 | #: src/widgets/universe_controls.ui:187 365 | msgid "_Keyboard Shortcuts" 366 | msgstr "Snel_toetsen" 367 | 368 | #: src/widgets/universe_controls.ui:191 369 | msgid "_About Game of Life" 370 | msgstr "_Over Game of Life" 371 | 372 | #: src/widgets/universe_controls.ui:195 373 | msgid "_Close" 374 | msgstr "_Sluiten" 375 | 376 | #: src/widgets/new_universe_view.ui:4 377 | msgid "New universe" 378 | msgstr "Nieuw universum" 379 | 380 | #: src/widgets/new_universe_view.ui:36 381 | msgid "Empty universe" 382 | msgstr "Leeg universum" 383 | 384 | #: src/widgets/new_universe_view.ui:42 385 | msgid "Random seed" 386 | msgstr "Willekeurige seed" 387 | 388 | #: src/widgets/new_universe_view.ui:53 389 | msgid "Template" 390 | msgstr "Sjabloon" 391 | 392 | #: src/widgets/new_universe_view.ui:64 393 | msgid "Glider" 394 | msgstr "Vlieger" 395 | 396 | #: src/widgets/new_universe_view.ui:65 397 | msgid "Pulsar" 398 | msgstr "Pulsar" 399 | 400 | #: src/widgets/new_universe_view.ui:66 401 | msgid "Quadpole" 402 | msgstr "Quadpaal" 403 | 404 | #: src/widgets/new_universe_view.ui:67 405 | msgid "Spaceship" 406 | msgstr "Ruimteschip" 407 | 408 | #: src/widgets/new_universe_view.ui:68 409 | msgid "Circle of fire" 410 | msgstr "Vuurcirkel" 411 | 412 | #: src/widgets/new_universe_view.ui:80 413 | msgid "Cancel" 414 | msgstr "Annuleren" 415 | 416 | #: src/widgets/new_universe_view.ui:89 417 | msgid "Create" 418 | msgstr "Aanmaken" 419 | 420 | #: src/widgets/preferences_window.ui:6 421 | msgid "General" 422 | msgstr "Algemeen" 423 | 424 | #: src/widgets/preferences_window.ui:10 425 | msgid "Feedbacks" 426 | msgstr "Feedback" 427 | 428 | #: src/widgets/preferences_window.ui:11 429 | msgid "Various application feedbacks settings" 430 | msgstr "Verscheidene feedbackinstallingen voor de app" 431 | 432 | #: src/widgets/preferences_window.ui:14 433 | msgid "Design hint" 434 | msgstr "Ontwerphint" 435 | 436 | #: src/widgets/preferences_window.ui:16 437 | msgid "Show a toast describing interaction modes during design mode" 438 | msgstr "" 439 | "Toont een toast-melding tijdens de ontwerpmodus welke interactiemodussen " 440 | "beschrijft" 441 | 442 | #: src/widgets/preferences_window.ui:32 443 | msgid "Universe" 444 | msgstr "Universum" 445 | 446 | #: src/widgets/preferences_window.ui:36 447 | msgid "Appearance" 448 | msgstr "Uiterlijk" 449 | 450 | #: src/widgets/preferences_window.ui:39 451 | msgid "Light colors" 452 | msgstr "Lichte kleuren" 453 | 454 | #: src/widgets/preferences_window.ui:40 455 | msgid "" 456 | "These colors are applied if you use a light scheme color on your desktop" 457 | msgstr "Deze kleuren worden gebruikt bij lichte modus" 458 | 459 | #: src/widgets/preferences_window.ui:64 460 | msgid "Dark colors" 461 | msgstr "Donkere kleuren" 462 | 463 | #: src/widgets/preferences_window.ui:65 464 | msgid "These colors are applied if you use a dark scheme color on your desktop" 465 | msgstr "Deze kleuren worden gebruikt bij donkere modus" 466 | 467 | #: src/widgets/preferences_window.ui:89 468 | msgid "Draw cells outline" 469 | msgstr "Celomtrek tekenen" 470 | 471 | #: src/widgets/preferences_window.ui:102 472 | msgid "Fade out dead cells" 473 | msgstr "Dode cellen uitvagen" 474 | 475 | #: src/widgets/preferences_window.ui:115 476 | msgid "Render on resize" 477 | msgstr "Tekenen bij veranderen grootte" 478 | 479 | #: src/widgets/preferences_window.ui:118 480 | msgid "" 481 | "Allows rendering the grid during a resize event of the application window. " 482 | "May affect performance." 483 | msgstr "" 484 | "Staat het tekenen van het raster toe bij het vergroten of verkleinen van het " 485 | "app-venster. Kan de prestaties beïnvloeden." 486 | 487 | #: src/widgets/preferences_window.ui:133 488 | msgid "Evolution" 489 | msgstr "Evolutie" 490 | 491 | #: src/widgets/preferences_window.ui:136 492 | msgid "Evolutions speed" 493 | msgstr "Evolutiesnelheid" 494 | 495 | #: src/widgets/preferences_window.ui:138 496 | msgid "The number of generations to be computed per second during an evolution" 497 | msgstr "Het aantal berekende generaties per seconde tijdens evolutie" 498 | -------------------------------------------------------------------------------- /po/pt_BR.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the game-of-life package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: game-of-life\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2023-03-03 15:13+0100\n" 12 | "PO-Revision-Date: 2025-02-16 22:35-0300\n" 13 | "Last-Translator: johnpeter19 \n" 14 | "Language-Team: \n" 15 | "Language: pt_BR\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "X-Generator: Poedit 3.5\n" 20 | 21 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:3 22 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:6 23 | msgid "Game of Life" 24 | msgstr "Jogo da vida" 25 | 26 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:4 27 | msgid "Game of Life Simulator" 28 | msgstr "Simulador da Jogo da vida" 29 | 30 | #: data/com.github.sixpounder.GameOfLife.desktop.in.in:12 31 | msgid "simulation;game;" 32 | msgstr "simulação; jogo;" 33 | 34 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:7 35 | msgid "Play Conway's Game of Life" 36 | msgstr "Jogue o jogo de vida de Conway" 37 | 38 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:9 39 | msgid "" 40 | "Game of Life lets you simulate simple universes made of cells that can be " 41 | "alive or dead, and evolve according to simple rules." 42 | msgstr "" 43 | "O jogo da vida permite simular universos simples feitos de células que podem " 44 | "estar vivas ou mortas e evoluir de acordo com as regras simples." 45 | 46 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:13 47 | msgid "Current features:" 48 | msgstr "Recursos atuais:" 49 | 50 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:17 51 | msgid "Random seed universes" 52 | msgstr "Universos de sementes aleatórias" 53 | 54 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:18 55 | msgid "Provide start templates" 56 | msgstr "Forneça modelos de início" 57 | 58 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:19 59 | msgid "Manually edit universes" 60 | msgstr "Editar manualmente universos" 61 | 62 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:20 63 | msgid "Save and restore snapshots" 64 | msgstr "Salvar e restaurar instantâneos" 65 | 66 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:39 67 | msgid "Andrea Coronese" 68 | msgstr "Andrea Coronese" 69 | 70 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:55 71 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:68 72 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:81 73 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:94 74 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:110 75 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:123 76 | msgid "This release addresses the followings:" 77 | msgstr "Esta versão aborda os seguintes:" 78 | 79 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:57 80 | msgid "More consistent UI" 81 | msgstr "UI mais consistente" 82 | 83 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:60 84 | msgid "Dutch translations (thanks Philip Goto)" 85 | msgstr "Traduções holandesas (obrigado Philip Goto)" 86 | 87 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:70 88 | msgid "Feature: step forward one generation" 89 | msgstr "Recurso: Avanço de uma geração" 90 | 91 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:73 92 | msgid "Group design tools in revealer" 93 | msgstr "Ferramentas de design de grupo no revendedor" 94 | 95 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:83 96 | msgid "New icon (thanks to Tobias Bernard)" 97 | msgstr "Novo ícone (obrigado a Tobias Bernard)" 98 | 99 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:86 100 | msgid "Reduce close button size" 101 | msgstr "Reduza o tamanho do botão fechar" 102 | 103 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:96 104 | msgid "Fixes main menu button shape" 105 | msgstr "FIXE a forma do botão do menu principal" 106 | 107 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:99 108 | msgid "Fixes a few problems with the main menu entries" 109 | msgstr "Corrige alguns problemas com as entradas do menu principal" 110 | 111 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:103 112 | msgid "Layout changes" 113 | msgstr "Alterações no layout" 114 | 115 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:112 116 | msgid "Fixes templates not being loaded" 117 | msgstr "Modelos de correções não estão sendo carregados" 118 | 119 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:115 120 | msgid "Moves grid rendering to gtk4 render node api" 121 | msgstr "Move a renderização da grade para o GTK4 renderize API do nó" 122 | 123 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:125 124 | msgid "Allow for cells fade out when they die" 125 | msgstr "Permita que as células desapareçam quando elas morrem" 126 | 127 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:128 128 | msgid "Performance issues on edge cases" 129 | msgstr "Problemas de desempenho em casos de borda" 130 | 131 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:131 132 | msgid "gtk4/glib/libadwaita stack upgrade" 133 | msgstr "Atualização da pilha gtk4/glib/libadwaita" 134 | 135 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:139 136 | msgid "Translations:" 137 | msgstr "Traduções:" 138 | 139 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:141 140 | msgid "Add french translation (Rene Coty)" 141 | msgstr "Adicione a tradução em francês (Rene Coty)" 142 | 143 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:147 144 | msgid "This is a revision addressing a few problems" 145 | msgstr "Esta é uma revisão abordando alguns problemas" 146 | 147 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:149 148 | msgid "Fix interaction bugs" 149 | msgstr "Corrija erros de interação" 150 | 151 | #: data/com.github.sixpounder.GameOfLife.appdata.xml.in.in:150 152 | msgid "Minor performance tweaks" 153 | msgstr "Ajustes de desempenho menores" 154 | 155 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:18 156 | msgid "Fades out cells when they die instead of deleting them in one go" 157 | msgstr "" 158 | "Desaparece as células quando elas morrem em vez de excluí -las de uma só vez" 159 | 160 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:22 161 | msgid "" 162 | "The number of generations per seconds that should be computed when a " 163 | "simulation is running" 164 | msgstr "" 165 | "O número de gerações por segundos que devem ser calculadas quando uma " 166 | "simulação estiver em execução" 167 | 168 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:32 169 | msgid "The width of the universe being generated, in cells number" 170 | msgstr "A largura do universo que está sendo gerada, no número das células" 171 | 172 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:36 173 | msgid "The height of the universe being generated, in cells number" 174 | msgstr "A altura do universo que está sendo gerada, no número das células" 175 | 176 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:40 177 | msgid "Wheter to draw cells outline in universe grid" 178 | msgstr "Se deve desenhar o contorno das células na grade do universo." 179 | 180 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:44 181 | msgid "" 182 | "Wheter to allow universe rendering when the application window is resizing" 183 | msgstr "" 184 | "Se deve permitir a renderização do universo quando a janela do aplicativo " 185 | "estiver redimensionando" 186 | 187 | #: data/com.github.sixpounder.GameOfLife.gschema.xml:48 188 | msgid "Wheter to show an interaction hint on design mode activated" 189 | msgstr "Se deve mostrar uma dica de interação no modo de design ativado" 190 | 191 | #: src/gtk/help-overlay.ui:11 192 | msgctxt "shortcut window" 193 | msgid "General" 194 | msgstr "Em geral" 195 | 196 | #: src/gtk/help-overlay.ui:14 197 | msgctxt "shortcut window" 198 | msgid "New Universe" 199 | msgstr "Novo universo" 200 | 201 | #: src/gtk/help-overlay.ui:20 202 | msgctxt "shortcut window" 203 | msgid "Open Snapshot" 204 | msgstr "Abrir instantâneo" 205 | 206 | #: src/gtk/help-overlay.ui:26 207 | msgctxt "shortcut window" 208 | msgid "Save Snapshot" 209 | msgstr "Salve o instantâneo" 210 | 211 | #: src/gtk/help-overlay.ui:32 212 | msgctxt "shortcut window" 213 | msgid "Preferences" 214 | msgstr "Preferências" 215 | 216 | #: src/gtk/help-overlay.ui:38 217 | msgctxt "shortcut window" 218 | msgid "Show Shortcuts" 219 | msgstr "Mostre atalhos" 220 | 221 | #: src/gtk/help-overlay.ui:44 222 | msgctxt "shortcut window" 223 | msgid "Close" 224 | msgstr "Fechar" 225 | 226 | #: src/gtk/help-overlay.ui:52 227 | msgctxt "shortcut window" 228 | msgid "Universe Control" 229 | msgstr "Controle do Universo" 230 | 231 | #: src/gtk/help-overlay.ui:55 232 | msgctxt "shortcut window" 233 | msgid "Toggle Design Mode" 234 | msgstr "Modo de design de alternância" 235 | 236 | #: src/gtk/help-overlay.ui:61 237 | msgctxt "shortcut window" 238 | msgid "Toggle Run Universe" 239 | msgstr "Alternar universo" 240 | 241 | #: src/gtk/help-overlay.ui:67 242 | msgctxt "shortcut window" 243 | msgid "Seed Universe" 244 | msgstr "Universo semente" 245 | 246 | #: src/window.rs:317 247 | msgid "Left click to make a cell alive, right click to make it dead" 248 | msgstr "" 249 | "Clique esquerdo para tornar uma célula viva, clique com o botão direito para " 250 | "deixá -lo morto" 251 | 252 | #: src/window.rs:320 253 | msgid "Do not show again" 254 | msgstr "Não mostre de novo" 255 | 256 | #: src/window.rs:340 257 | msgid "_Save" 258 | msgstr "_Salvar" 259 | 260 | #: src/window.rs:341 src/window.rs:399 261 | msgid "_Cancel" 262 | msgstr "_Cancelar" 263 | 264 | #: src/window.rs:343 265 | msgid "Save universe snapshot" 266 | msgstr "Salvar instantâneo do universo" 267 | 268 | #: src/window.rs:368 269 | msgid "Unable to write to file" 270 | msgstr "Incapaz de escrever para arquivo" 271 | 272 | #: src/window.rs:374 273 | msgid "Unable to serialize snapshot" 274 | msgstr "Incapaz de serializar o instantâneo" 275 | 276 | #: src/window.rs:398 277 | msgid "_Open" 278 | msgstr "_Abrir" 279 | 280 | #: src/window.rs:401 281 | msgid "Open universe snapshot" 282 | msgstr "Abrir instantâneo do universo." 283 | 284 | #: src/window.rs:430 src/window.rs:436 285 | msgid "Unreadable file" 286 | msgstr "Arquivo ilegível" 287 | 288 | #: src/window.rs:441 289 | msgid "File not existing or not accessible" 290 | msgstr "Arquivo não existente ou não acessível" 291 | 292 | #: src/window.rs:483 293 | msgid "Bad template data" 294 | msgstr "Dados de modelo ruim" 295 | 296 | #: src/window.rs:489 297 | msgid "Template not found" 298 | msgstr "Modelo não encontrado" 299 | 300 | #: src/widgets/universe_controls.ui:53 301 | msgctxt "a11y" 302 | msgid "Toggle design mode" 303 | msgstr "Modo de design de alternância" 304 | 305 | #: src/widgets/universe_controls.ui:62 306 | msgid "Toggle design tools" 307 | msgstr "Alternante ferramentas de design" 308 | 309 | #: src/widgets/universe_controls.ui:74 310 | msgid "Cell brush" 311 | msgstr "Escova de células" 312 | 313 | #: src/widgets/universe_controls.ui:80 314 | msgctxt "a11y" 315 | msgid "Cell brush" 316 | msgstr "Escova de células" 317 | 318 | #: src/widgets/universe_controls.ui:87 319 | msgid "Randomly seed this universe" 320 | msgstr "Semente aleatória este universo" 321 | 322 | #: src/widgets/universe_controls.ui:97 323 | msgctxt "a11y" 324 | msgid "Randomly seed this universe" 325 | msgstr "Semente aleatória este universo" 326 | 327 | #: src/widgets/universe_controls.ui:110 328 | msgid "Toggle universe run" 329 | msgstr "Alternar execução do universo." 330 | 331 | #: src/widgets/universe_controls.ui:118 332 | msgctxt "a11y" 333 | msgid "Toggle universe run" 334 | msgstr "Alternar execução do universo." 335 | 336 | #: src/widgets/universe_controls.ui:125 337 | msgid "Skip forward one generation" 338 | msgstr "Pule para frente uma geração" 339 | 340 | #: src/widgets/universe_controls.ui:135 341 | msgctxt "a11y" 342 | msgid "Skip forward one generation" 343 | msgstr "Pule para frente uma geração" 344 | 345 | #: src/widgets/universe_controls.ui:169 346 | msgid "_New Universe" 347 | msgstr "_Novo universo" 348 | 349 | #: src/widgets/universe_controls.ui:173 350 | msgid "_Open Snapshot" 351 | msgstr "_Abrir instantâneo" 352 | 353 | #: src/widgets/universe_controls.ui:177 354 | msgid "_Save Snapshot" 355 | msgstr "_Salve o instantâneo" 356 | 357 | #: src/widgets/universe_controls.ui:183 358 | msgid "_Preferences" 359 | msgstr "_Preferências" 360 | 361 | #: src/widgets/universe_controls.ui:187 362 | msgid "_Keyboard Shortcuts" 363 | msgstr "_Atalhos de teclado" 364 | 365 | #: src/widgets/universe_controls.ui:191 366 | msgid "_About Game of Life" 367 | msgstr "_Sobre o Jogo da Vida" 368 | 369 | #: src/widgets/universe_controls.ui:195 370 | msgid "_Close" 371 | msgstr "_Fechar" 372 | 373 | #: src/widgets/new_universe_view.ui:4 374 | msgid "New universe" 375 | msgstr "Novo universo" 376 | 377 | #: src/widgets/new_universe_view.ui:36 378 | msgid "Empty universe" 379 | msgstr "Universo vazio" 380 | 381 | #: src/widgets/new_universe_view.ui:42 382 | msgid "Random seed" 383 | msgstr "Semente aleatória" 384 | 385 | #: src/widgets/new_universe_view.ui:53 386 | msgid "Template" 387 | msgstr "Modelo" 388 | 389 | #: src/widgets/new_universe_view.ui:64 390 | msgid "Glider" 391 | msgstr "Planador" 392 | 393 | #: src/widgets/new_universe_view.ui:65 394 | msgid "Pulsar" 395 | msgstr "Pulsar" 396 | 397 | #: src/widgets/new_universe_view.ui:66 398 | msgid "Quadpole" 399 | msgstr "Quadrupolo" 400 | 401 | #: src/widgets/new_universe_view.ui:67 402 | msgid "Spaceship" 403 | msgstr "Espaço" 404 | 405 | #: src/widgets/new_universe_view.ui:68 406 | msgid "Circle of fire" 407 | msgstr "Círculo de Fogo" 408 | 409 | #: src/widgets/new_universe_view.ui:80 410 | msgid "Cancel" 411 | msgstr "Cancelar" 412 | 413 | #: src/widgets/new_universe_view.ui:89 414 | msgid "Create" 415 | msgstr "Criar" 416 | 417 | #: src/widgets/preferences_window.ui:6 418 | msgid "General" 419 | msgstr "Em geral" 420 | 421 | #: src/widgets/preferences_window.ui:10 422 | msgid "Feedbacks" 423 | msgstr "Feedbacks" 424 | 425 | #: src/widgets/preferences_window.ui:11 426 | msgid "Various application feedbacks settings" 427 | msgstr "Várias configurações de feedbacks de aplicativos" 428 | 429 | #: src/widgets/preferences_window.ui:14 430 | msgid "Design hint" 431 | msgstr "Dica de design" 432 | 433 | #: src/widgets/preferences_window.ui:16 434 | msgid "Show a toast describing interaction modes during design mode" 435 | msgstr "" 436 | "Mostre uma torrada descrevendo os modos de interação durante o modo de design" 437 | 438 | #: src/widgets/preferences_window.ui:32 439 | msgid "Universe" 440 | msgstr "Universo" 441 | 442 | #: src/widgets/preferences_window.ui:36 443 | msgid "Appearance" 444 | msgstr "Aparência" 445 | 446 | #: src/widgets/preferences_window.ui:39 447 | msgid "Light colors" 448 | msgstr "Cores claras" 449 | 450 | #: src/widgets/preferences_window.ui:40 451 | msgid "" 452 | "These colors are applied if you use a light scheme color on your desktop" 453 | msgstr "" 454 | "Essas cores são aplicadas se você usar uma cor de esquema de luz na sua área " 455 | "de trabalho" 456 | 457 | #: src/widgets/preferences_window.ui:64 458 | msgid "Dark colors" 459 | msgstr "Cores escuras" 460 | 461 | #: src/widgets/preferences_window.ui:65 462 | msgid "These colors are applied if you use a dark scheme color on your desktop" 463 | msgstr "" 464 | "Essas cores são aplicadas se você usar uma cor do tema escuro em sua área de " 465 | "trabalho" 466 | 467 | #: src/widgets/preferences_window.ui:89 468 | msgid "Draw cells outline" 469 | msgstr "Desenhe o esboço das células" 470 | 471 | #: src/widgets/preferences_window.ui:102 472 | msgid "Fade out dead cells" 473 | msgstr "Desbotado células mortas" 474 | 475 | #: src/widgets/preferences_window.ui:115 476 | msgid "Render on resize" 477 | msgstr "Renderizar em redimensionar" 478 | 479 | #: src/widgets/preferences_window.ui:118 480 | msgid "" 481 | "Allows rendering the grid during a resize event of the application window. " 482 | "May affect performance." 483 | msgstr "" 484 | "Permite renderizar a grade durante um evento de redimensionamento da janela " 485 | "do aplicativo. Pode afetar o desempenho." 486 | 487 | #: src/widgets/preferences_window.ui:133 488 | msgid "Evolution" 489 | msgstr "Evolução" 490 | 491 | #: src/widgets/preferences_window.ui:136 492 | msgid "Evolutions speed" 493 | msgstr "Velocidade da evolução" 494 | 495 | #: src/widgets/preferences_window.ui:138 496 | msgid "The number of generations to be computed per second during an evolution" 497 | msgstr "O número de gerações a ser calculado por segundo durante uma evolução" 498 | --------------------------------------------------------------------------------