Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 74af1336e8 | |||
| 88b0afa319 | |||
| 4d487ed872 | |||
| e9d6631159 |
@ -28,22 +28,7 @@ build_meson:
|
||||
- ninja -C _build install
|
||||
|
||||
build_deb:
|
||||
tags:
|
||||
- librem5
|
||||
stage: build
|
||||
artifacts:
|
||||
paths:
|
||||
- "*.deb"
|
||||
script:
|
||||
- apt-get -y install devscripts
|
||||
- debuild -i -us -uc -b
|
||||
- cp ../*.deb .
|
||||
|
||||
build_deb_aarch64:
|
||||
image: multiarch/debian-debootstrap:arm64-buster
|
||||
tags:
|
||||
- ARM64
|
||||
allow_failure: true
|
||||
<<: *tags
|
||||
stage: build
|
||||
artifacts:
|
||||
paths:
|
||||
|
||||
22
HACKING.md
22
HACKING.md
@ -25,7 +25,7 @@ sudo apt-get -y build-dep .
|
||||
```
|
||||
|
||||
For an explicit list of dependencies check the `Build-Depends` entry in the
|
||||
[`debian/control`](./debian/control) file.
|
||||
[debian/control][] file.
|
||||
|
||||
Testing
|
||||
-------
|
||||
@ -62,24 +62,6 @@ $ gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'us'), ('xkb',
|
||||
Coding
|
||||
------
|
||||
|
||||
### Project structure
|
||||
|
||||
Rust modules should be split into 2 categories: libraries, and user interface. They differ in the way they do error handling.
|
||||
|
||||
Libraries should:
|
||||
|
||||
- not panic due to external surprises, only due to internal inconsistencies
|
||||
- pass errors and surprises they can't handle to the callers instead
|
||||
- not silence errors and surprises
|
||||
|
||||
User interface modules should:
|
||||
|
||||
- try to provide safe values whenever they encounter an error
|
||||
- do the logging
|
||||
- give libraries the ability to report errors and surprises (e.g. via giving them loggers)
|
||||
|
||||
### Style
|
||||
|
||||
Code submitted should roughly match the style of surrounding code. Things that will *not* be accepted are ones that often lead to errors:
|
||||
|
||||
- skipping brackets `{}` after every `if()`, `else`, and similar
|
||||
@ -140,8 +122,6 @@ sh /source_path/cargo.sh test
|
||||
|
||||
### Cargo dependencies
|
||||
|
||||
All Cargo dependencies must be selected in the version available in PureOS, and added to the file `debian/control`. Please check with https://software.pureos.net/search_pkg?term=librust .
|
||||
|
||||
Dependencies must be specified in `Cargo.toml` with 2 numbers: "major.minor". Since bugfix version number is meant to not affect the interface, this allows for safe updates.
|
||||
|
||||
`Cargo.lock` is used for remembering the revisions of all Rust dependencies. It should be updated often, preferably with each bugfix revision, and in a commit on its own:
|
||||
|
||||
@ -1,11 +1,18 @@
|
||||
# Maintained by: Mark Müller <markmueller86@gmail.com>
|
||||
---
|
||||
bounds: { x: 0, y: 1, width: 360, height: 208 }
|
||||
|
||||
outlines:
|
||||
default: { width: 35.33, height: 52 }
|
||||
altline: { width: 52.67, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
spaceline: { width: 99.67, height: 52 }
|
||||
special: { width: 35.33, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 35.33, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 52.67, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 99.67, height: 52 }
|
||||
special:
|
||||
bounds: { x: 0, y: 0, width: 35.33, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,11 +1,18 @@
|
||||
# Maintained by: Mark Müller <markmueller86@gmail.com>
|
||||
---
|
||||
bounds: { x: 0, y: 1, width: 540, height: 168 }
|
||||
|
||||
outlines:
|
||||
default: { width: 48, height: 42 }
|
||||
altline: { width: 81, height: 42 }
|
||||
wide: { width: 108, height: 42 }
|
||||
spaceline: { width: 216, height: 42 }
|
||||
special: { width: 48, height: 42 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 48, height: 42 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 81, height: 42 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 108, height: 42 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 216, height: 42 }
|
||||
special:
|
||||
bounds: { x: 0, y: 0, width: 48, height: 42 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -2,12 +2,19 @@
|
||||
# University of the Aegean, Department of Mathematics, atsol@aegean.gr
|
||||
# Sep 2019
|
||||
---
|
||||
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
|
||||
|
||||
outlines:
|
||||
default: { width: 32, height: 52 }
|
||||
altline: { width: 48.39024, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
outline7: { width: 88.97561, height: 52 }
|
||||
spaceline: { width: 150.5853, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 32, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
outline7:
|
||||
bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 150.5853, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
---
|
||||
bounds: { x: 0, y: 1, width: 360, height: 210 }
|
||||
|
||||
outlines:
|
||||
default: { width: 35.33, height: 52 }
|
||||
altline: { width: 52.67, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
spaceline: { width: 99.67, height: 52 }
|
||||
special: { width: 44, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 35.33, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 52.67, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 99.67, height: 52 }
|
||||
special:
|
||||
bounds: { x: 0, y: 0, width: 44, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
---
|
||||
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
|
||||
|
||||
outlines:
|
||||
default: { width: 32, height: 52 }
|
||||
altline: { width: 48.39024, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
outline7: { width: 88.97561, height: 52 }
|
||||
spaceline: { width: 150.5853, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 32, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
outline7:
|
||||
bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 150.5853, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,12 +1,19 @@
|
||||
# Italian layout created by Antonio Pandolfo
|
||||
# 03 october 2019
|
||||
---
|
||||
bounds: { x: 0, y: 1, width: 360, height: 210 }
|
||||
|
||||
outlines:
|
||||
default: { width: 35.33, height: 52 }
|
||||
altline: { width: 52.67, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
spaceline: { width: 99.67, height: 52 }
|
||||
special: { width: 44, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 35.33, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 52.67, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 99.67, height: 52 }
|
||||
special:
|
||||
bounds: { x: 0, y: 0, width: 44, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,11 +1,18 @@
|
||||
# Maintained by: Mark Müller <markmueller86@gmail.com>
|
||||
---
|
||||
bounds: { x: 0, y: 1, width: 360, height: 208 }
|
||||
|
||||
outlines:
|
||||
default: { width: 62, height: 52 }
|
||||
default-wide: { width: 62, height: 52 }
|
||||
altline: { width: 62, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
special: { width: 62, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
default-wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
special:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
|
||||
views:
|
||||
base: # hiragana
|
||||
|
||||
@ -1,11 +1,18 @@
|
||||
# Maintained by: Mark Müller <markmueller86@gmail.com>
|
||||
---
|
||||
bounds: { x: 0, y: 1, width: 540, height: 168 }
|
||||
|
||||
outlines:
|
||||
default: { width: 62, height: 42 }
|
||||
default-wide: { width: 62, height: 42 }
|
||||
altline: { width: 62, height: 42 }
|
||||
wide: { width: 62, height: 42 }
|
||||
special: { width: 62, height: 42 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 42 }
|
||||
default-wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 42 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 42 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 42 }
|
||||
special:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 42 }
|
||||
|
||||
views:
|
||||
base: # hiragana
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
---
|
||||
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
|
||||
|
||||
outlines:
|
||||
default: { width: 32, height: 52 }
|
||||
altline: { width: 48.39024, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
outline7: { width: 88.97561, height: 52 }
|
||||
spaceline: { width: 150.5853, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 32, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
outline7:
|
||||
bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 150.5853, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
---
|
||||
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
|
||||
|
||||
outlines:
|
||||
default: { width: 37.46341, height: 52 }
|
||||
altline: { width: 48.39024, height: 52 }
|
||||
outline7: { width: 88.97561, height: 52 }
|
||||
spaceline: { width: 120.5853, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 37.46341, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
|
||||
outline7:
|
||||
bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 120.5853, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
---
|
||||
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
|
||||
|
||||
outlines:
|
||||
default: { width: 32, height: 52 }
|
||||
altline: { width: 48.39024, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
outline7: { width: 88.97561, height: 52 }
|
||||
spaceline: { width: 150.5853, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 32, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 48.39024, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
outline7:
|
||||
bounds: { x: 0, y: 0, width: 88.97561, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 150.5853, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
---
|
||||
bounds: { x: 0, y: 1, width: 360, height: 208 }
|
||||
|
||||
outlines:
|
||||
default: { width: 35.33, height: 52 }
|
||||
altline: { width: 52.67, height: 52 }
|
||||
wide: { width: 62, height: 52 }
|
||||
spaceline: { width: 142, height: 52 }
|
||||
special: { width: 44, height: 52 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 35.33, height: 52 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 52.67, height: 52 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 62, height: 52 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 142, height: 52 }
|
||||
special:
|
||||
bounds: { x: 0, y: 0, width: 44, height: 52 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
---
|
||||
bounds: { x: 0, y: 1, width: 540, height: 168 }
|
||||
|
||||
outlines:
|
||||
default: { width: 54, height: 42 }
|
||||
altline: { width: 81, height: 42 }
|
||||
wide: { width: 108, height: 42 }
|
||||
spaceline: { width: 216, height: 42 }
|
||||
special: { width: 54, height: 42 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 54, height: 42 }
|
||||
altline:
|
||||
bounds: { x: 0, y: 0, width: 81, height: 42 }
|
||||
wide:
|
||||
bounds: { x: 0, y: 0, width: 108, height: 42 }
|
||||
spaceline:
|
||||
bounds: { x: 0, y: 0, width: 216, height: 42 }
|
||||
special:
|
||||
bounds: { x: 0, y: 0, width: 54, height: 42 }
|
||||
|
||||
views:
|
||||
base:
|
||||
|
||||
50
debian/changelog
vendored
50
debian/changelog
vendored
@ -1,53 +1,3 @@
|
||||
squeekboard (1.5.0) amber-phone; urgency=medium
|
||||
|
||||
[ Dorota Czaplejewicz ]
|
||||
* keycodes: Sort to eliminate runtime indeterminism
|
||||
* switcher: Switch layout on menu item click
|
||||
* Drop squeek_key
|
||||
* renderer: Remove some unneeded vars
|
||||
* renderer: Simplified outline rendering
|
||||
* renderer: Drop row from button rendering
|
||||
* renderer: Drop unused params
|
||||
* renderer: Simplify surface rendering
|
||||
* rendering: Simplify Cairo context usage, remove unneeded calls.
|
||||
* rendering: Remove unneeded redraw after button release
|
||||
* renderer: Remove unused locked key render function
|
||||
* renderer: Simply cut off when painting outside bounds
|
||||
* renderer: Render whole keyboard the same way as pressed buttons
|
||||
|
||||
[ Mark Müller ]
|
||||
* layout: add German wide layout
|
||||
|
||||
[ Dorota Czaplejewicz ]
|
||||
* renderer: Remove unused functions
|
||||
* cleanup: Remove references to squeek_view
|
||||
* cleanup: Unbox View and Row
|
||||
* cleanup: Remove unused single frame draw
|
||||
* positioning: Calculate sizes instead of storing, move position out of widgets
|
||||
* positioning: Clean up unused code
|
||||
* Fix old Rust woes
|
||||
|
||||
[ Mark Müller ]
|
||||
* layout: add Japanese Kana wide layout
|
||||
|
||||
[ Dorota Czaplejewicz ]
|
||||
* Entry test: Add Terminal input purpose
|
||||
* readme: Add note about Cargo dependencies
|
||||
* Create a library/UI module separation
|
||||
* hacking: Add DCO and licensing requirement
|
||||
* Fix internal .md link
|
||||
|
||||
[ Mark Müller ]
|
||||
* squeekboard-test-layout: add argument parsing and some more output
|
||||
|
||||
[ Dorota Czaplejewicz ]
|
||||
* Use clap in the lockfile
|
||||
* parsing: Remove bounds which weren't used anyway
|
||||
* layout: Respect margins
|
||||
* CI: Build arm64 .deb
|
||||
|
||||
-- Dorota Czaplejewicz <dorota.czaplejewicz@puri.sm> Mon, 23 Dec 2019 11:58:57 +0000
|
||||
|
||||
squeekboard (1.4.0) amber-phone; urgency=medium
|
||||
|
||||
* "text" property in layouts
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
project(
|
||||
'squeekboard',
|
||||
'c', 'rust',
|
||||
version: '1.5.0',
|
||||
version: '1.4.0',
|
||||
license: 'GPLv3',
|
||||
meson_version: '>=0.51.0',
|
||||
default_options: [
|
||||
|
||||
62
src/data.rs
62
src/data.rs
@ -1,7 +1,5 @@
|
||||
/**! The parsing of the data files for layouts */
|
||||
|
||||
// TODO: find a nice way to make sure non-positive sizes don't break layouts
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{ HashMap, HashSet };
|
||||
use std::env;
|
||||
@ -218,20 +216,21 @@ fn load_layout_data_with_fallback(
|
||||
#[derive(Debug, Deserialize, PartialEq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Layout {
|
||||
#[serde(default)]
|
||||
margins: Margins,
|
||||
/// FIXME: deprecate in favor of margins
|
||||
bounds: Bounds,
|
||||
views: HashMap<String, Vec<ButtonIds>>,
|
||||
#[serde(default)]
|
||||
buttons: HashMap<String, ButtonMeta>,
|
||||
outlines: HashMap<String, Outline>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct Margins {
|
||||
top: f64,
|
||||
bottom: f64,
|
||||
side: f64,
|
||||
struct Bounds {
|
||||
x: f64,
|
||||
y: f64,
|
||||
width: f64,
|
||||
height: f64,
|
||||
}
|
||||
|
||||
/// Buttons are embedded in a single string
|
||||
@ -272,8 +271,8 @@ enum Action {
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct Outline {
|
||||
width: f64,
|
||||
height: f64,
|
||||
/// FIXME: replace with Size
|
||||
bounds: Bounds,
|
||||
}
|
||||
|
||||
/// Errors encountered loading the layout into yaml
|
||||
@ -461,10 +460,10 @@ impl Layout {
|
||||
},
|
||||
// FIXME: use a dedicated field
|
||||
margins: layout::Margins {
|
||||
top: self.margins.top,
|
||||
left: self.margins.side,
|
||||
bottom: self.margins.bottom,
|
||||
right: self.margins.side,
|
||||
top: self.bounds.x,
|
||||
left: self.bounds.y,
|
||||
bottom: 0.0,
|
||||
right: self.bounds.y,
|
||||
},
|
||||
}),
|
||||
warning_handler,
|
||||
@ -650,7 +649,9 @@ fn create_button<H: WarningHandler>(
|
||||
warning_handler.handle(
|
||||
&format!("No default outline defined! Using 1x1!")
|
||||
);
|
||||
Outline { width: 1f64, height: 1f64 }
|
||||
Outline {
|
||||
bounds: Bounds { x: 0f64, y: 0f64, width: 1f64, height: 1f64 },
|
||||
}
|
||||
});
|
||||
|
||||
layout::Button {
|
||||
@ -658,8 +659,8 @@ fn create_button<H: WarningHandler>(
|
||||
outline_name: CString::new(outline_name).expect("Bad outline"),
|
||||
// TODO: do layout before creating buttons
|
||||
size: layout::Size {
|
||||
width: outline.width,
|
||||
height: outline.height,
|
||||
width: outline.bounds.width,
|
||||
height: outline.bounds.height,
|
||||
},
|
||||
label: label,
|
||||
state: state,
|
||||
@ -685,7 +686,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
Layout::from_file(PathBuf::from("tests/layout.yaml")).unwrap(),
|
||||
Layout {
|
||||
margins: Margins { top: 0f64, bottom: 0f64, side: 0f64 },
|
||||
bounds: Bounds { x: 0f64, y: 0f64, width: 0f64, height: 0f64 },
|
||||
views: hashmap!(
|
||||
"base".into() => vec!("test".into()),
|
||||
),
|
||||
@ -700,7 +701,11 @@ mod tests {
|
||||
}
|
||||
},
|
||||
outlines: hashmap!{
|
||||
"default".into() => Outline { width: 0f64, height: 0f64 },
|
||||
"default".into() => Outline {
|
||||
bounds: Bounds {
|
||||
x: 0f64, y: 0f64, width: 0f64, height: 0f64
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
@ -850,21 +855,4 @@ mod tests {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_layout_margins() {
|
||||
let out = Layout::from_file(PathBuf::from("tests/layout_margins.yaml"))
|
||||
.unwrap()
|
||||
.build(PanicWarn).0
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
out.margins,
|
||||
layout::Margins {
|
||||
top: 1.0,
|
||||
bottom: 3.0,
|
||||
left: 2.0,
|
||||
right: 2.0,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,8 +102,12 @@ pub mod c {
|
||||
imservice.pending = IMProtocolState {
|
||||
content_hint: {
|
||||
ContentHint::from_bits(hint).unwrap_or_else(|| {
|
||||
eprintln!("Warning: received invalid hint flags");
|
||||
ContentHint::NONE
|
||||
let out = ContentHint::from_bits_truncate(hint);
|
||||
eprintln!(
|
||||
"Warning: received hint flags with unknown bits set: 0x{:x}",
|
||||
hint ^ out.bits(),
|
||||
);
|
||||
out
|
||||
})
|
||||
},
|
||||
content_purpose: {
|
||||
@ -141,6 +145,16 @@ pub mod c {
|
||||
{
|
||||
let imservice = check_imservice(imservice, im).unwrap();
|
||||
let active_changed = imservice.current.active ^ imservice.pending.active;
|
||||
|
||||
fn is_visible(state: &IMProtocolState) -> bool {
|
||||
state.active
|
||||
&& !state.content_hint.contains(
|
||||
ContentHint::ON_SCREEN_INPUT_PROVIDED
|
||||
)
|
||||
}
|
||||
|
||||
let visible_changed = is_visible(&imservice.current)
|
||||
^ is_visible(&imservice.pending);
|
||||
|
||||
imservice.serial += Wrapping(1u32);
|
||||
imservice.current = imservice.pending.clone();
|
||||
@ -148,13 +162,18 @@ pub mod c {
|
||||
active: imservice.current.active,
|
||||
..IMProtocolState::default()
|
||||
};
|
||||
if active_changed {
|
||||
if imservice.current.active {
|
||||
|
||||
if active_changed && imservice.current.active {
|
||||
eekboard_context_service_set_hint_purpose(
|
||||
imservice.ui_manager,
|
||||
imservice.current.content_hint.bits(),
|
||||
imservice.current.content_purpose.clone() as u32,
|
||||
);
|
||||
}
|
||||
|
||||
if visible_changed {
|
||||
if is_visible(&imservice.current) {
|
||||
eekboard_context_service_show_keyboard(imservice.ui_manager);
|
||||
eekboard_context_service_set_hint_purpose(
|
||||
imservice.ui_manager,
|
||||
imservice.current.content_hint.bits(),
|
||||
imservice.current.content_purpose.clone() as u32);
|
||||
} else {
|
||||
eekboard_context_service_hide_keyboard(imservice.ui_manager);
|
||||
}
|
||||
@ -219,6 +238,7 @@ bitflags!{
|
||||
const SENSITIVE_DATA = 0x80;
|
||||
const LATIN = 0x100;
|
||||
const MULTILINE = 0x200;
|
||||
const ON_SCREEN_INPUT_PROVIDED = 0x400;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
119
src/layout.rs
119
src/layout.rs
@ -99,7 +99,7 @@ pub mod c {
|
||||
}
|
||||
}
|
||||
|
||||
/// Translate and then scale
|
||||
/// Scale + translate
|
||||
#[repr(C)]
|
||||
pub struct Transformation {
|
||||
pub origin_x: f64,
|
||||
@ -108,14 +108,6 @@ pub mod c {
|
||||
}
|
||||
|
||||
impl Transformation {
|
||||
/// Applies the new transformation after this one
|
||||
pub fn chain(self, next: Transformation) -> Transformation {
|
||||
Transformation {
|
||||
origin_x: self.origin_x + self.scale * next.origin_x,
|
||||
origin_y: self.origin_y + self.scale * next.origin_y,
|
||||
scale: self.scale * next.scale,
|
||||
}
|
||||
}
|
||||
fn forward(&self, p: Point) -> Point {
|
||||
Point {
|
||||
x: (p.x - self.origin_x) / self.scale,
|
||||
@ -203,8 +195,7 @@ pub mod c {
|
||||
println!("{:?}", button);
|
||||
}
|
||||
|
||||
/// Positions the layout contents within the available space.
|
||||
/// The origin of the transformation is the point inside the margins.
|
||||
/// Positions the layout within the available space
|
||||
#[no_mangle]
|
||||
pub extern "C"
|
||||
fn squeek_layout_calculate_transformation(
|
||||
@ -213,10 +204,15 @@ pub mod c {
|
||||
allocation_height: f64,
|
||||
) -> Transformation {
|
||||
let layout = unsafe { &*layout };
|
||||
layout.calculate_transformation(Size {
|
||||
width: allocation_width,
|
||||
height: allocation_height,
|
||||
})
|
||||
let size = layout.calculate_size();
|
||||
let h_scale = allocation_width / size.width;
|
||||
let v_scale = allocation_height / size.height;
|
||||
let scale = if h_scale < v_scale { h_scale } else { v_scale };
|
||||
Transformation {
|
||||
origin_x: (allocation_width - (scale * size.width)) / 2.0,
|
||||
origin_y: (allocation_height - (scale * size.height)) / 2.0,
|
||||
scale: scale,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -431,7 +427,7 @@ pub struct ButtonPlace<'a> {
|
||||
offset: c::Point,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Size {
|
||||
pub width: f64,
|
||||
pub height: f64,
|
||||
@ -564,7 +560,6 @@ pub enum ArrangementKind {
|
||||
Wide = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Margins {
|
||||
pub top: f64,
|
||||
pub bottom: f64,
|
||||
@ -718,8 +713,7 @@ impl Layout {
|
||||
};
|
||||
}
|
||||
|
||||
/// Calculates size without margins
|
||||
fn calculate_inner_size(&self) -> Size {
|
||||
fn calculate_size(&self) -> Size {
|
||||
Size {
|
||||
height: find_max_double(
|
||||
self.views.iter(),
|
||||
@ -731,39 +725,6 @@ impl Layout {
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Size including margins
|
||||
fn calculate_size(&self) -> Size {
|
||||
let inner_size = self.calculate_inner_size();
|
||||
Size {
|
||||
width: self.margins.left + inner_size.width + self.margins.right,
|
||||
height: (
|
||||
self.margins.top
|
||||
+ inner_size.height
|
||||
+ self.margins.bottom
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_transformation(
|
||||
&self,
|
||||
available: Size,
|
||||
) -> c::Transformation {
|
||||
let size = self.calculate_size();
|
||||
let h_scale = available.width / size.width;
|
||||
let v_scale = available.height / size.height;
|
||||
let scale = if h_scale < v_scale { h_scale } else { v_scale };
|
||||
let outside_margins = c::Transformation {
|
||||
origin_x: (available.width - (scale * size.width)) / 2.0,
|
||||
origin_y: (available.height - (scale * size.height)) / 2.0,
|
||||
scale: scale,
|
||||
};
|
||||
outside_margins.chain(c::Transformation {
|
||||
origin_x: self.margins.left,
|
||||
origin_y: self.margins.top,
|
||||
scale: 1.0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
mod procedures {
|
||||
@ -946,58 +907,4 @@ mod test {
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_bottom_margin() {
|
||||
// just one button
|
||||
let view = View::new(vec![
|
||||
(
|
||||
0.0,
|
||||
Row {
|
||||
angle: 0,
|
||||
buttons: vec![(
|
||||
0.0,
|
||||
Box::new(Button {
|
||||
size: Size { width: 1.0, height: 1.0 },
|
||||
..*make_button_with_state("foo".into(), make_state())
|
||||
}),
|
||||
)]
|
||||
},
|
||||
),
|
||||
]);
|
||||
let layout = Layout {
|
||||
current_view: String::new(),
|
||||
keymap_str: CString::new("").unwrap(),
|
||||
kind: ArrangementKind::Base,
|
||||
locked_keys: HashSet::new(),
|
||||
pressed_keys: HashSet::new(),
|
||||
// Lots of bottom margin
|
||||
margins: Margins {
|
||||
top: 0.0,
|
||||
left: 0.0,
|
||||
right: 0.0,
|
||||
bottom: 1.0,
|
||||
},
|
||||
views: hashmap! {
|
||||
String::new() => view,
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
layout.calculate_inner_size(),
|
||||
Size { width: 1.0, height: 1.0 }
|
||||
);
|
||||
assert_eq!(
|
||||
layout.calculate_size(),
|
||||
Size { width: 1.0, height: 2.0 }
|
||||
);
|
||||
// Don't change those values randomly!
|
||||
// They take advantage of incidental precise float representation
|
||||
// to even be comparable.
|
||||
let transformation = layout.calculate_transformation(
|
||||
Size { width: 2.0, height: 2.0 }
|
||||
);
|
||||
assert_eq!(transformation.scale, 1.0);
|
||||
assert_eq!(transformation.origin_x, 0.5);
|
||||
assert_eq!(transformation.origin_y, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,19 @@ except AttributeError:
|
||||
print("Terminal purpose not available on this GTK version", file=sys.stderr)
|
||||
terminal = []
|
||||
|
||||
def new_grid(items, set_type):
|
||||
grid = Gtk.Grid(orientation='vertical', column_spacing=8, row_spacing=8)
|
||||
i = 0
|
||||
for text, value in items:
|
||||
l = Gtk.Label(label=text)
|
||||
e = Gtk.Entry(hexpand=True)
|
||||
set_type(e, value)
|
||||
grid.attach(l, 0, i, 1, 1)
|
||||
grid.attach(e, 1, i, 1, 1)
|
||||
i += 1
|
||||
return grid
|
||||
|
||||
|
||||
class App(Gtk.Application):
|
||||
|
||||
purposes = [
|
||||
@ -27,20 +40,23 @@ class App(Gtk.Application):
|
||||
("PIN", Gtk.InputPurpose.PIN),
|
||||
] + terminal
|
||||
|
||||
hints = [
|
||||
("OSK provided", Gtk.InputHints.INHIBIT_OSK)
|
||||
]
|
||||
|
||||
def do_activate(self):
|
||||
w = Gtk.ApplicationWindow(application=self)
|
||||
grid = Gtk.Grid(orientation='vertical', column_spacing=8, row_spacing=8)
|
||||
i = 0
|
||||
for text, purpose in self.purposes:
|
||||
notebook = Gtk.Notebook()
|
||||
def add_purpose(entry, purpose):
|
||||
entry.set_input_purpose(purpose)
|
||||
def add_hint(entry, hint):
|
||||
entry.set_input_hints(hint)
|
||||
purpose_grid = new_grid(self.purposes, add_purpose)
|
||||
hint_grid = new_grid(self.hints, add_hint)
|
||||
|
||||
l = Gtk.Label(label=text)
|
||||
e = Gtk.Entry(hexpand=True)
|
||||
e.set_input_purpose(purpose)
|
||||
grid.attach(l, 0, i, 1, 1)
|
||||
grid.attach(e, 1, i, 1, 1)
|
||||
i += 1
|
||||
|
||||
w.add(grid)
|
||||
notebook.append_page(purpose_grid, Gtk.Label(label="Purposes"))
|
||||
notebook.append_page(hint_grid, Gtk.Label(label="Hints"))
|
||||
w.add(notebook)
|
||||
w.show_all()
|
||||
|
||||
app = App()
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
---
|
||||
bounds:
|
||||
x: 0
|
||||
y: 0
|
||||
width: 0
|
||||
height: 0
|
||||
views:
|
||||
base:
|
||||
- "test"
|
||||
outlines:
|
||||
default: { width: 0, height: 0 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
buttons:
|
||||
test:
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
---
|
||||
# missing views
|
||||
bounds:
|
||||
x: 0
|
||||
y: 0
|
||||
width: 0
|
||||
height: 0
|
||||
outlines:
|
||||
default: { width: 0, height: 0 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
---
|
||||
# extra field
|
||||
bounds:
|
||||
x: 0
|
||||
y: 0
|
||||
width: 0
|
||||
height: 0
|
||||
views:
|
||||
base:
|
||||
- "test"
|
||||
outlines:
|
||||
default: { width: 0, height: 0 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
bad_field: false
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
---
|
||||
# punctuation
|
||||
bounds:
|
||||
x: 0
|
||||
y: 0
|
||||
width: 0
|
||||
height: 0
|
||||
views:
|
||||
base:
|
||||
- "."
|
||||
outlines:
|
||||
default: { width: 0, height: 0 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
buttons:
|
||||
".":
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
---
|
||||
# punctuation
|
||||
bounds:
|
||||
x: 0
|
||||
y: 0
|
||||
width: 0
|
||||
height: 0
|
||||
views:
|
||||
base:
|
||||
- "å"
|
||||
outlines:
|
||||
default: { width: 0, height: 0 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
buttons:
|
||||
å:
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
---
|
||||
# punctuation
|
||||
bounds:
|
||||
x: 0
|
||||
y: 0
|
||||
width: 0
|
||||
height: 0
|
||||
views:
|
||||
base:
|
||||
- "か゚" # 2 codepoints
|
||||
outlines:
|
||||
default: { width: 0, height: 0 }
|
||||
default:
|
||||
bounds: { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
# Margins present
|
||||
margins: { top: 1, side: 2, bottom: 3 }
|
||||
views:
|
||||
base:
|
||||
- "test"
|
||||
outlines:
|
||||
default: { width: 1, height: 1 }
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
---
|
||||
# Margins present
|
||||
margins: { top: 1, side: 2, bottom: 3 }
|
||||
views:
|
||||
base:
|
||||
- "test"
|
||||
outlines:
|
||||
default: { width: 1, height: 1 }
|
||||
|
||||
Reference in New Issue
Block a user