Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

+SDL2, -winit #79

Merged
merged 10 commits into from
Mar 28, 2021
Merged
1,148 changes: 303 additions & 845 deletions Cargo.lock

Large diffs are not rendered by default.

21 changes: 18 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,23 @@ edition = "2018"
#skulpin = { version = "0.10.0", default-features = false, features = ["skia_complete", "skulpin_winit"] }
#skulpin = { path = "../skulpin", default-features = false, features = ["skia_complete", "skulpin_winit"] }
#skulpin-plugin-imgui = { path = "../skulpin/skulpin-plugin-imgui" }
skulpin = { version = "0.11.2", default-features = false, features = ["skia_complete", "skulpin_winit", "winit-22"] }
skulpin-plugin-imgui = { version = "0.7.1" }
imgui-winit-support = "0.5.0"
skulpin = { version = "0.13.0" }
skulpin-renderer = "0.13.0"

# For windowing, contexts, and events
sdl2 = { version = ">=0.33", features = ["bundled", "static-link", "raw-window-handle"] }

# For choosing font for toolbox
font-kit = "0.10.0"

# For global state
lazy_static = "1.4.0"

# For immediate mode GUI
imgui = "0.7.0"
imgui-sdl2 = "0.14.0"
imgui-skia-renderer = {git = "https://github.com/MFEK/imgui-skia-renderer.rlib", branch = "main"}

# For argument parsing
clap = "2.33.3"
git-version = "0.3.4"
Expand Down Expand Up @@ -60,8 +67,16 @@ MFEKMath = { git = "https://github.com/MFEK/math", branch = "vws-testing" }
#glifparser = { path = "../glifparser" } # for development
mfek-ipc = { git = "https://github.com/mfek/ipc" }

#xml parsing
xmltree = "0.10.1"

#config file directory resolution
app_dirs = "1.2.1"

#converting enums to strings
strum = "0.20"
strum_macros = "0.20"

# See src/util/mod.rs::set_codepage_utf8
[target.'cfg(windows)'.dependencies]
winapi = "0.3"
65 changes: 65 additions & 0 deletions src/command/default_keymap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!--
Example binding:
<binding command = "ToolPen" keycode = "A"/>

Commands:

// zoom
ResetScale
ZoomIn
ZoomOut

// move camera
NudgeUp
NudgeDown
NudgeLeft
NudgeRight

// tools
ToolPen
ToolSelect
ToolZoom
ToolVWS

// view modes
TogglePointLabels
TogglePreviewMode

// mod
ShiftMod
CtrlMod
-->

<keybindings>
<!-- zoom -->
<binding command = "ResetScale" key = "1"/>
<binding command = "ZoomIn" key = "="/>
<binding command = "ZoomOut" key = "-"/>

<!-- move camera -->
<binding command = "NudgeUp" key = "Up"/>
<binding command = "NudgeDown" key = "Down"/>
<binding command = "NudgeLeft" key = "Left"/>
<binding command = "NudgeRight" key = "Right"/>

<!-- tools -->
<binding command = "ToolPen" key = "A"/>
<binding command = "ToolPen" key = "P"/>
<binding command = "ToolSelect" key = "V"/>
<binding command = "ToolZoom" key = "Z"/>
<binding command = "ToolVWS" key = "S"/>

<!-- view modes -->
<binding command = "TogglePointLabels" key = "3"/>
<binding command = "TogglePreviewMode" key = "`"/>

<!-- console -->
<binding command = "ToggleConsole" key = ";"/>

<!-- mod keys -->
<mod name = "ShiftMod" key = "LShift"/>
<mod name = "CtrlMod" key = "LCtrl"/>

<mod name = "ShiftMod" key = "RShift"/>
<mod name = "CtrlMod" key = "RCtrl"/>
</keybindings>
173 changes: 173 additions & 0 deletions src/command/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
use app_dirs::*;
use sdl2::keyboard::Keycode;
use std::fs::read_to_string;
use std::path::Path;
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
str::FromStr,
};
use strum_macros::{Display, EnumString};
use xmltree;

// a command file is put into the user's config directory upon first run
// <command name="ToolPen" key = "A">
// <mod name= "Shift" key = "shift">
#[derive(Copy, Clone, EnumString, Display, Debug, PartialEq)]
pub enum Command {
// zoom
ResetScale,
ZoomIn,
ZoomOut,

// move camera
NudgeUp,
NudgeDown,
NudgeLeft,
NudgeRight,

// tools
ToolPen,
ToolSelect,
ToolZoom,
ToolVWS,

// view modes
TogglePointLabels,
TogglePreviewMode,

// console
ToggleConsole,

ShiftMod,
CtrlMod,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CommandMod {
pub shift: bool,
pub ctrl: bool,
}

pub struct CommandInfo {
pub command: Command,
pub command_mod: CommandMod,
}

pub fn initialize_keybinds() {
let binding_xml = load_keybinding_xml();
let mut config =
xmltree::Element::parse(binding_xml.as_bytes()).expect("Invalid keybinding XML!");

let mut hm = HashMap::new();
while let Some(binding) = config.take_child("binding") {
let keycode = binding
.attributes
.get("key")
.expect("Binding does not have a key associated!");
let command = binding
.attributes
.get("command")
.expect("Binding does not have a command associated!");

let command_enum = Command::from_str(command).expect("Invalid command string!");
let keycode_enum =
sdl2::keyboard::Keycode::from_name(keycode).expect("Invalid keycode string!");

hm.insert(keycode_enum, command_enum);
}

KEYMAP.with(|v| {
v.borrow_mut().keybindings = hm;
})
}

pub fn keycode_to_command(keycode: &Keycode, keys_down: &HashSet<Keycode>) -> Option<CommandInfo> {
let command_enum = KEYMAP.with(|v| {
if let Some(key) = v.borrow().keybindings.get(keycode) {
return Some(*key);
}

None
});

println!("{:?} {:?}", command_enum, keycode);
if let Some(command_enum) = command_enum {
return Some(CommandInfo {
command: command_enum,
command_mod: key_down_to_mod(keys_down),
});
}

return None;
}

// kinda clunky but it works
pub fn key_down_to_mod(keys_down: &HashSet<Keycode>) -> CommandMod {
let mut keymod = CommandMod {
shift: false,
ctrl: false,
};

KEYMAP.with(|v| {
for (key, value) in v.borrow().keybindings.iter() {
match value {
Command::ShiftMod => {
if keys_down.get(&key).is_some() {
keymod.shift = true;
}
}
Command::CtrlMod => {
if keys_down.get(&key).is_some() {
keymod.ctrl = true;
}
}
_ => {}
}
}
});

return keymod;
}

fn load_keybinding_xml() -> String {
// check for a keybinding file in our local directory first
let config_path = Path::new("./keybindings.xml");
let config_string = read_to_string(&config_path);

if let Ok(config_string) = config_string {
return config_string;
}

// Next we check in an OS appropriate app directory
let config_path = app_dir(AppDataType::UserConfig, &APP_INFO, "glif");

if let Ok(mut pb) = config_path {
pb.push("keybindings");
pb.set_extension("xml");

let path = pb.as_path();
let config_string = read_to_string(path);

if let Ok(config_string) = config_string {
return config_string;
}
}

// We didn't find either so we're gonna return our default
DEFAULT_KEYBINDINGS.to_owned()
}

const APP_INFO: AppInfo = AppInfo {
name: "MFEK",
author: "MFEK team",
};
const DEFAULT_KEYBINDINGS: &str = include_str!("default_keymap.xml");

struct KeyData {
keybindings: HashMap<Keycode, Command>,
}

thread_local! {
static KEYMAP: RefCell<KeyData> = RefCell::new(KeyData{ keybindings: HashMap::new() });
}
16 changes: 6 additions & 10 deletions src/events/console/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,16 @@ use log::debug;

mod commands;

use crate::winit::event::{ModifiersState, VirtualKeyCode};
use sdl2::keyboard::Keycode;
use sdl2::keyboard::Mod;

// Only called if ElementState::Pressed
pub fn set_state(vk: VirtualKeyCode, m: ModifiersState) {
pub fn set_state(vk: Keycode, m: Mod) {
CONSOLE.with(|c| match vk {
VirtualKeyCode::Semicolon => {
if !m.shift() {
return;
}
c.borrow_mut().active(true);
}
VirtualKeyCode::Escape => {
Keycode::Escape => {
c.borrow_mut().active(false);
}
VirtualKeyCode::Return => {
Keycode::Return => {
if c.borrow().active {
run_command(&mut c.borrow_mut());
}
Expand Down
41 changes: 21 additions & 20 deletions src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,26 @@ pub mod vws;
pub mod zoom;

pub use self::zoom::{zoom_in_factor, zoom_out_factor};

use crate::command::CommandMod;
use sdl2::keyboard::Mod;
use sdl2::video::Window;
use sdl2::{mouse::MouseButton, Sdl};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MouseMeta {
pub modifiers: ModifiersState,
pub modifiers: CommandMod,
pub button: MouseButton,
}

// Generic events
pub fn center_cursor(winit_window: &Window) -> Result<(), winit::error::ExternalError> {
let mut center = winit_window.inner_size();
center.width /= 2;
center.height /= 2;
STATE.with(|v| {
v.borrow_mut().absolute_mousepos = PhysicalPosition::from((center.width, center.height))
});
winit_window.set_cursor_position(winit::dpi::PhysicalPosition::new(
center.width as i32,
center.height as i32,
))
pub fn center_cursor(sdl_context: &Sdl, sdl_window: &Window) {
let mut center = sdl_window.size();
center.0 /= 2;
center.1 /= 2;
STATE.with(|v| v.borrow_mut().absolute_mousepos = (center.0 as f64, center.1 as f64));

sdl_context
.mouse()
.warp_mouse_in_window(&sdl_window, center.0 as i32, center.1 as i32);
}

pub fn update_viewport<T>(
Expand All @@ -50,19 +51,19 @@ pub fn update_viewport<T>(
}

pub fn update_mousepos<T>(
position: PhysicalPosition<f64>,
position: (f64, f64),
v: &RefCell<state::State<T>>,
pan: bool,
) -> PhysicalPosition<f64> {
) -> (f64, f64) {
let factor = 1. / v.borrow().factor as f64;
let uoffset = v.borrow().offset;
let offset = (uoffset.0 as f64, uoffset.1 as f64);

let absolute_mposition = PhysicalPosition::from(((position.x).floor(), (position.y).floor()));
let mposition = PhysicalPosition::from((
((position.x).floor() - offset.0) * factor,
((position.y).floor() - offset.1) * factor,
));
let absolute_mposition = ((position.0).floor(), (position.1).floor());
let mposition = (
((position.0).floor() - offset.0) * factor,
((position.1).floor() - offset.1) * factor,
);

v.borrow_mut().absolute_mousepos = absolute_mposition;
v.borrow_mut().mousepos = mposition;
Expand Down
6 changes: 3 additions & 3 deletions src/events/pan.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// Pan
use super::prelude::*;

pub fn mouse_moved<T>(position: PhysicalPosition<f64>, v: &RefCell<state::State<T>>) -> bool {
pub fn mouse_moved<T>(position: (f64, f64), v: &RefCell<state::State<T>>) -> bool {
let old_mposition = v.borrow().absolute_mousepos.clone();
let mut offset = v.borrow().offset;
let mposition = update_mousepos(position, &v, true);
if !v.borrow().mousedown {
return false;
}
offset.0 += (mposition.x - old_mposition.x).floor() as f32;
offset.1 += (mposition.y - old_mposition.y).floor() as f32;
offset.0 += (mposition.0 - old_mposition.0).floor() as f32;
offset.1 += (mposition.1 - old_mposition.1).floor() as f32;
//offset = (mposition.x as f32, mposition.y as f32);
v.borrow_mut().offset = offset;
update_viewport(None, None, &v);
Expand Down
Loading