Control and Alt are special in that they aren't expected to switch levels, and so don't need to change what characters are output. Use in layouts by adding `modifier: Control` or `modifier: Alt` in place of `text: "foo"`. The latching of the modifier will force the keyboard to emit raw key presses and prevent it from outputting text.
128 lines
3.5 KiB
Rust
128 lines
3.5 KiB
Rust
/*! Drawing the UI */
|
|
|
|
use cairo;
|
|
use std::cell::RefCell;
|
|
|
|
use ::action::Action;
|
|
use ::keyboard;
|
|
use ::layout::{ Button, Layout };
|
|
use ::layout::c::{ EekGtkKeyboard, Point };
|
|
use ::submission::Submission;
|
|
|
|
use glib::translate::FromGlibPtrNone;
|
|
use gtk::WidgetExt;
|
|
|
|
mod c {
|
|
use super::*;
|
|
|
|
use cairo_sys;
|
|
use std::os::raw::c_void;
|
|
|
|
// This is constructed only in C, no need for warnings
|
|
#[allow(dead_code)]
|
|
#[repr(transparent)]
|
|
#[derive(Clone, Copy)]
|
|
pub struct EekRenderer(*const c_void);
|
|
|
|
#[no_mangle]
|
|
extern "C" {
|
|
// Button and View inside CButtonPlace are safe to pass to C
|
|
// as long as they don't outlive the call
|
|
// and nothing dereferences them
|
|
#[allow(improper_ctypes)]
|
|
pub fn eek_render_button(
|
|
renderer: EekRenderer,
|
|
cr: *mut cairo_sys::cairo_t,
|
|
button: *const Button,
|
|
pressed: u64,
|
|
locked: u64,
|
|
);
|
|
}
|
|
|
|
/// Draws all buttons that are not in the base state
|
|
#[no_mangle]
|
|
pub extern "C"
|
|
fn squeek_layout_draw_all_changed(
|
|
layout: *mut Layout,
|
|
renderer: EekRenderer,
|
|
cr: *mut cairo_sys::cairo_t,
|
|
submission: *const Submission,
|
|
) {
|
|
let layout = unsafe { &mut *layout };
|
|
let submission = unsafe { &*submission };
|
|
let cr = unsafe { cairo::Context::from_raw_none(cr) };
|
|
let active_modifiers = submission.get_active_modifiers();
|
|
|
|
layout.foreach_visible_button(|offset, button| {
|
|
let state = RefCell::borrow(&button.state).clone();
|
|
let active_mod = match &state.action {
|
|
Action::ApplyModifier(m) => active_modifiers.contains(m),
|
|
_ => false,
|
|
};
|
|
let locked = state.action.is_active(&layout.current_view)
|
|
| active_mod;
|
|
if state.pressed == keyboard::PressType::Pressed || locked {
|
|
render_button_at_position(
|
|
renderer, &cr,
|
|
offset,
|
|
button.as_ref(),
|
|
state.pressed, locked,
|
|
);
|
|
}
|
|
})
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C"
|
|
fn squeek_draw_layout_base_view(
|
|
layout: *mut Layout,
|
|
renderer: EekRenderer,
|
|
cr: *mut cairo_sys::cairo_t,
|
|
) {
|
|
let layout = unsafe { &mut *layout };
|
|
let cr = unsafe { cairo::Context::from_raw_none(cr) };
|
|
|
|
layout.foreach_visible_button(|offset, button| {
|
|
render_button_at_position(
|
|
renderer, &cr,
|
|
offset,
|
|
button.as_ref(),
|
|
keyboard::PressType::Released, false,
|
|
);
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Renders a button at a position (button's own bounds ignored)
|
|
pub fn render_button_at_position(
|
|
renderer: c::EekRenderer,
|
|
cr: &cairo::Context,
|
|
position: Point,
|
|
button: &Button,
|
|
pressed: keyboard::PressType,
|
|
locked: bool,
|
|
) {
|
|
cr.save();
|
|
cr.translate(position.x, position.y);
|
|
cr.rectangle(
|
|
0.0, 0.0,
|
|
button.size.width, button.size.height
|
|
);
|
|
cr.clip();
|
|
unsafe {
|
|
c::eek_render_button(
|
|
renderer,
|
|
cairo::Context::to_raw_none(&cr),
|
|
button as *const Button,
|
|
pressed as u64,
|
|
locked as u64,
|
|
)
|
|
};
|
|
cr.restore();
|
|
}
|
|
|
|
pub fn queue_redraw(keyboard: EekGtkKeyboard) {
|
|
let widget = unsafe { gtk::Widget::from_glib_none(keyboard.0) };
|
|
widget.queue_draw();
|
|
}
|