Compare commits

..

10 Commits

Author SHA1 Message Date
d76deb0655 Release 1.5.0 "The bends"
This release introduces some renderer improvements, including relating to speed.

Mire importantly, layout files have an incompatible change in format: bounds on the layout are replaced by margins. This removes the possibility that buttons don't fit in the layout and frees layout makers from having to calculate the size of the layout manually.
2019-12-23 12:08:45 +00:00
3b0456b5cd Merge branch 'margins' into 'master'
Use margins, remove bounds

See merge request Librem5/squeekboard!283
2019-12-23 11:56:30 +00:00
77a6ca1900 Merge branch 'arm64' into 'master'
CI: Build arm64 .deb

See merge request Librem5/squeekboard!292
2019-12-20 08:32:54 +00:00
c0331434d7 CI: Build arm64 .deb 2019-12-19 19:38:34 +00:00
f335ea92d4 Merge branch 'readme' into 'master'
Readme updates

See merge request Librem5/squeekboard!281
2019-12-18 19:49:59 +00:00
257b97e9ca layout: Respect margins 2019-12-15 18:43:56 +00:00
5e700219f9 parsing: Remove bounds which weren't used anyway 2019-12-15 18:43:56 +00:00
d5c8f32088 Fix internal .md link 2019-12-11 15:50:28 +00:00
7641b4da6f Create a library/UI module separation 2019-12-11 15:33:29 +00:00
a84730198d readme: Add note about Cargo dependencies 2019-12-11 15:26:27 +00:00
29 changed files with 338 additions and 292 deletions

View File

@ -28,7 +28,22 @@ build_meson:
- ninja -C _build install
build_deb:
<<: *tags
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
stage: build
artifacts:
paths:

View File

@ -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][] file.
[`debian/control`](./debian/control) file.
Testing
-------
@ -62,6 +62,24 @@ $ 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
@ -122,6 +140,8 @@ 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:

View File

@ -1,18 +1,11 @@
# Maintained by: Mark Müller <markmueller86@gmail.com>
---
bounds: { x: 0, y: 1, width: 360, height: 208 }
outlines:
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 }
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 }
views:
base:

View File

@ -1,18 +1,11 @@
# Maintained by: Mark Müller <markmueller86@gmail.com>
---
bounds: { x: 0, y: 1, width: 540, height: 168 }
outlines:
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 }
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 }
views:
base:

View File

@ -2,19 +2,12 @@
# University of the Aegean, Department of Mathematics, atsol@aegean.gr
# Sep 2019
---
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
outlines:
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 }
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 }
views:
base:

View File

@ -1,17 +1,10 @@
---
bounds: { x: 0, y: 1, width: 360, height: 210 }
outlines:
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 }
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 }
views:
base:

View File

@ -1,17 +1,10 @@
---
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
outlines:
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 }
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 }
views:
base:

View File

@ -1,19 +1,12 @@
# Italian layout created by Antonio Pandolfo
# 03 october 2019
---
bounds: { x: 0, y: 1, width: 360, height: 210 }
outlines:
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 }
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 }
views:
base:

View File

@ -1,18 +1,11 @@
# Maintained by: Mark Müller <markmueller86@gmail.com>
---
bounds: { x: 0, y: 1, width: 360, height: 208 }
outlines:
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 }
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 }
views:
base: # hiragana

View File

@ -1,18 +1,11 @@
# Maintained by: Mark Müller <markmueller86@gmail.com>
---
bounds: { x: 0, y: 1, width: 540, height: 168 }
outlines:
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 }
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 }
views:
base: # hiragana

View File

@ -1,17 +1,10 @@
---
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
outlines:
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 }
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 }
views:
base:

View File

@ -1,15 +1,9 @@
---
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
outlines:
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 }
default: { width: 37.46341, height: 52 }
altline: { width: 48.39024, height: 52 }
outline7: { width: 88.97561, height: 52 }
spaceline: { width: 120.5853, height: 52 }
views:
base:

View File

@ -1,17 +1,10 @@
---
bounds: { x: 0, y: 0.33, width: 360, height: 210 }
outlines:
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 }
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 }
views:
base:

View File

@ -1,17 +1,10 @@
---
bounds: { x: 0, y: 1, width: 360, height: 208 }
outlines:
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 }
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 }
views:
base:

View File

@ -1,17 +1,10 @@
---
bounds: { x: 0, y: 1, width: 540, height: 168 }
outlines:
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 }
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 }
views:
base:

50
debian/changelog vendored
View File

@ -1,3 +1,53 @@
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

View File

@ -1,7 +1,7 @@
project(
'squeekboard',
'c', 'rust',
version: '1.4.0',
version: '1.5.0',
license: 'GPLv3',
meson_version: '>=0.51.0',
default_options: [

View File

@ -1,5 +1,7 @@
/**! 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;
@ -216,21 +218,20 @@ fn load_layout_data_with_fallback(
#[derive(Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct Layout {
/// FIXME: deprecate in favor of margins
bounds: Bounds,
#[serde(default)]
margins: Margins,
views: HashMap<String, Vec<ButtonIds>>,
#[serde(default)]
buttons: HashMap<String, ButtonMeta>,
outlines: HashMap<String, Outline>
}
#[derive(Debug, Clone, Deserialize, PartialEq)]
#[derive(Debug, Clone, Deserialize, PartialEq, Default)]
#[serde(deny_unknown_fields)]
struct Bounds {
x: f64,
y: f64,
width: f64,
height: f64,
struct Margins {
top: f64,
bottom: f64,
side: f64,
}
/// Buttons are embedded in a single string
@ -271,8 +272,8 @@ enum Action {
#[derive(Debug, Clone, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct Outline {
/// FIXME: replace with Size
bounds: Bounds,
width: f64,
height: f64,
}
/// Errors encountered loading the layout into yaml
@ -460,10 +461,10 @@ impl Layout {
},
// FIXME: use a dedicated field
margins: layout::Margins {
top: self.bounds.x,
left: self.bounds.y,
bottom: 0.0,
right: self.bounds.y,
top: self.margins.top,
left: self.margins.side,
bottom: self.margins.bottom,
right: self.margins.side,
},
}),
warning_handler,
@ -649,9 +650,7 @@ fn create_button<H: WarningHandler>(
warning_handler.handle(
&format!("No default outline defined! Using 1x1!")
);
Outline {
bounds: Bounds { x: 0f64, y: 0f64, width: 1f64, height: 1f64 },
}
Outline { width: 1f64, height: 1f64 }
});
layout::Button {
@ -659,8 +658,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.bounds.width,
height: outline.bounds.height,
width: outline.width,
height: outline.height,
},
label: label,
state: state,
@ -686,7 +685,7 @@ mod tests {
assert_eq!(
Layout::from_file(PathBuf::from("tests/layout.yaml")).unwrap(),
Layout {
bounds: Bounds { x: 0f64, y: 0f64, width: 0f64, height: 0f64 },
margins: Margins { top: 0f64, bottom: 0f64, side: 0f64 },
views: hashmap!(
"base".into() => vec!("test".into()),
),
@ -701,11 +700,7 @@ mod tests {
}
},
outlines: hashmap!{
"default".into() => Outline {
bounds: Bounds {
x: 0f64, y: 0f64, width: 0f64, height: 0f64
},
}
"default".into() => Outline { width: 0f64, height: 0f64 },
},
}
);
@ -855,4 +850,21 @@ 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,
}
);
}
}

View File

@ -102,12 +102,8 @@ pub mod c {
imservice.pending = IMProtocolState {
content_hint: {
ContentHint::from_bits(hint).unwrap_or_else(|| {
let out = ContentHint::from_bits_truncate(hint);
eprintln!(
"Warning: received hint flags with unknown bits set: 0x{:x}",
hint ^ out.bits(),
);
out
eprintln!("Warning: received invalid hint flags");
ContentHint::NONE
})
},
content_purpose: {
@ -146,34 +142,19 @@ 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();
imservice.pending = IMProtocolState {
active: imservice.current.active,
..IMProtocolState::default()
};
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) {
if active_changed {
if imservice.current.active {
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);
}
@ -238,7 +219,6 @@ bitflags!{
const SENSITIVE_DATA = 0x80;
const LATIN = 0x100;
const MULTILINE = 0x200;
const ON_SCREEN_INPUT_PROVIDED = 0x400;
}
}

View File

@ -99,7 +99,7 @@ pub mod c {
}
}
/// Scale + translate
/// Translate and then scale
#[repr(C)]
pub struct Transformation {
pub origin_x: f64,
@ -108,6 +108,14 @@ 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,
@ -195,7 +203,8 @@ pub mod c {
println!("{:?}", button);
}
/// Positions the layout within the available space
/// Positions the layout contents within the available space.
/// The origin of the transformation is the point inside the margins.
#[no_mangle]
pub extern "C"
fn squeek_layout_calculate_transformation(
@ -204,15 +213,10 @@ pub mod c {
allocation_height: f64,
) -> Transformation {
let layout = unsafe { &*layout };
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,
}
layout.calculate_transformation(Size {
width: allocation_width,
height: allocation_height,
})
}
#[no_mangle]
@ -427,7 +431,7 @@ pub struct ButtonPlace<'a> {
offset: c::Point,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct Size {
pub width: f64,
pub height: f64,
@ -560,6 +564,7 @@ pub enum ArrangementKind {
Wide = 1,
}
#[derive(Debug, PartialEq)]
pub struct Margins {
pub top: f64,
pub bottom: f64,
@ -713,7 +718,8 @@ impl Layout {
};
}
fn calculate_size(&self) -> Size {
/// Calculates size without margins
fn calculate_inner_size(&self) -> Size {
Size {
height: find_max_double(
self.views.iter(),
@ -725,6 +731,39 @@ 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 {
@ -907,4 +946,58 @@ 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);
}
}

View File

@ -12,19 +12,6 @@ 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 = [
@ -40,23 +27,20 @@ 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)
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)
grid = Gtk.Grid(orientation='vertical', column_spacing=8, row_spacing=8)
i = 0
for text, purpose in self.purposes:
notebook.append_page(purpose_grid, Gtk.Label(label="Purposes"))
notebook.append_page(hint_grid, Gtk.Label(label="Hints"))
w.add(notebook)
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)
w.show_all()
app = App()

View File

@ -1,15 +1,9 @@
---
bounds:
x: 0
y: 0
width: 0
height: 0
views:
base:
- "test"
outlines:
default:
bounds: { x: 0, y: 0, width: 0, height: 0 }
default: { width: 0, height: 0 }
buttons:
test:

View File

@ -1,11 +1,5 @@
---
# missing views
bounds:
x: 0
y: 0
width: 0
height: 0
outlines:
default:
bounds: { x: 0, y: 0, width: 0, height: 0 }
default: { width: 0, height: 0 }

View File

@ -1,15 +1,9 @@
---
# extra field
bounds:
x: 0
y: 0
width: 0
height: 0
views:
base:
- "test"
outlines:
default:
bounds: { x: 0, y: 0, width: 0, height: 0 }
default: { width: 0, height: 0 }
bad_field: false

View File

@ -1,16 +1,10 @@
---
# punctuation
bounds:
x: 0
y: 0
width: 0
height: 0
views:
base:
- "."
outlines:
default:
bounds: { x: 0, y: 0, width: 0, height: 0 }
default: { width: 0, height: 0 }
buttons:
".":

View File

@ -1,16 +1,10 @@
---
# punctuation
bounds:
x: 0
y: 0
width: 0
height: 0
views:
base:
- "å"
outlines:
default:
bounds: { x: 0, y: 0, width: 0, height: 0 }
default: { width: 0, height: 0 }
buttons:
å:

View File

@ -1,14 +1,8 @@
---
# punctuation
bounds:
x: 0
y: 0
width: 0
height: 0
views:
base:
- "か゚" # 2 codepoints
outlines:
default:
bounds: { x: 0, y: 0, width: 0, height: 0 }
default: { width: 0, height: 0 }

View File

@ -0,0 +1,9 @@
---
# Margins present
margins: { top: 1, side: 2, bottom: 3 }
views:
base:
- "test"
outlines:
default: { width: 1, height: 1 }

View File

@ -0,0 +1,9 @@
---
# Margins present
margins: { top: 1, side: 2, bottom: 3 }
views:
base:
- "test"
outlines:
default: { width: 1, height: 1 }