Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
46a49131cThis file is pinned to the selected release. Download the original to open it in your design tool.
use std::time::Instant;
use std::sync::{
Arc,
RwLock,
};
use env;
use gtk;
use gtk::{
ContainerExt,
Inhibit,
OrientableExt,
WidgetExt,
BoxExt,
GtkWindowExt,
GLAreaExt,
Orientation::Vertical,
};
use gdk;
use gdk::{
EventMask,
ModifierType,
EventMotion,
EventKey,
EventButton
};
use relm::Widget;
use relm_attributes::widget;
use self::Msg::*;
use components::cursor_info;
use components::info_bar;
use components::cursor_info::CursorInfo;
use components::info_bar::InfoBar;
use copper::state::schema::*;
use copper::state::component_libraries::*;
use copper::state::event::{EventBus, Listener, EventMessage};
use copper::geometry::Point2D;
use copper::loading::schema_loader;
use copper::viewing::schema_viewer;
use copper::drawing::schema_drawer;
use copper::loading::component_libraries_loader;
pub struct Model {
view_state: Arc<RwLock<ViewState>>,
schema: Arc<RwLock<Schema>>,
event_bus: EventBus,
title: String,
frame_start: Instant,
}
#[derive(Msg)]
pub enum Msg {
Quit,
Realize,
Unrealize,
RenderGl(gdk::GLContext),
Resize(i32, i32, i32),
ButtonPressed(EventButton),
MoveCursor(EventMotion),
ZoomOnSchema(f64, f64),
KeyDown(EventKey)
}
#[widget]
impl Widget for Win {
fn init_view(&mut self) {
self.window.add_events(
EventMask::POINTER_MOTION_MASK.bits() as i32 |
EventMask::SCROLL_MASK.bits() as i32 |
EventMask::SMOOTH_SCROLL_MASK.bits() as i32 |
EventMask::BUTTON_PRESS_MASK.bits() as i32 |
EventMask::BUTTON_RELEASE_MASK.bits() as i32
);
self.gl_area.add_events(
EventMask::POINTER_MOTION_MASK.bits() as i32 |
EventMask::SCROLL_MASK.bits() as i32 |
EventMask::SMOOTH_SCROLL_MASK.bits() as i32 |
EventMask::BUTTON_PRESS_MASK.bits() as i32 |
EventMask::BUTTON_RELEASE_MASK.bits() as i32
);
let context = self.gl_area.get_context().unwrap().clone();
self.make_context_current(context);
}
// The initial model.
fn model() -> Model {
let event_bus = EventBus::new();
let view_state = Arc::new(RwLock::new(ViewState::new(1, 1)));
let schema = Arc::new(RwLock::new(Schema::new(event_bus.get_handle())));
let libraries = Arc::new(RwLock::new(ComponentLibraries::new(event_bus.get_handle())));
let args: Vec<String> = env::args().collect();
if args.len() != 3 {
println!("Please specify a .lib and a .sch file.");
::std::process::exit(1);
}
let mut libraries_loader = component_libraries_loader::ComponentLibrariesLoader::new(libraries.clone());
libraries_loader.load_from_file(&args[1]);
let drawer: Arc<RwLock<Listener>> = Arc::new(RwLock::new(schema_drawer::SchemaDrawer::new(schema.clone(), view_state.clone(), libraries.clone())));
let viewer: Arc<RwLock<Listener>> = Arc::new(RwLock::new(schema_viewer::SchemaViewer::new(schema.clone(), view_state.clone(), libraries.clone())));
event_bus.get_handle().add_listener(drawer);
event_bus.get_handle().add_listener(viewer);
// Load schema on boot for now
Self::load_schema(
&mut schema_loader::SchemaLoader::new(schema.clone()),
schema.clone(),
view_state.clone(),
libraries,
);
Model {
view_state,
schema,
event_bus,
title: "Schema Renderer".to_string(),
frame_start: Instant::now(),
}
}
// Update the model according to the message received.
fn update(&mut self, event: Msg) {
//println!("{:?}", event);
match event {
Quit => gtk::main_quit(),
Realize => println!("realize!"), // This will never be called because relm applies this handler after the event
Unrealize => println!("unrealize!"),
RenderGl(context) => {
self.model.frame_start = Instant::now();
self.make_context_current(context);
self.model.event_bus.get_handle().send(&EventMessage::DrawSchema);
let d = Instant::now() - self.model.frame_start;
self.info_bar.emit(info_bar::Msg::FrameTimeCaptured(d.as_secs() * 1e6 as u64 + d.subsec_micros() as u64));
//println!("Frame Duration {}", d.as_secs() * 1e6 as u64 + d.subsec_micros() as u64);
},
Resize(w,h, factor) => {
println!("RenderArea size - w: {}, h: {}", w, h);
{
let mut view_state = self.model.view_state.write().unwrap();
view_state.update_from_resize(w as u32, h as u32);
self.model.title = format!("Schema Renderer {:?}", Point2D::new(w as f32, h as f32));
view_state.update_display_scale_factor(factor);
self.model.event_bus.get_handle().send(&EventMessage::ResizeDrawArea(w as u16, h as u16));
}
self.notify_view_state_changed();
},
ButtonPressed(event) => {
println!("BTN DOWN {:?}", event.get_button());
if event.get_button() == 1 {
let mut view_state = self.model.view_state.write().unwrap();
view_state.select_hovered_component();
}
self.notify_view_state_changed();
},
MoveCursor(event) => {
{
let mut view_state = self.model.view_state.write().unwrap();
let (x, y) = event.get_position();
let new_state = Point2D::new(x as f32, y as f32);
if event.get_state().contains(ModifierType::BUTTON3_MASK) {
let mut movement = new_state - view_state.get_cursor();
movement.x /= view_state.width as f32 * view_state.get_aspect_ratio();
movement.y /= - view_state.height as f32;
view_state.center -= movement / view_state.scale * 8.0;
view_state.update_perspective();
}
view_state.update_cursor(new_state);
}
self.notify_view_state_changed();
},
ZoomOnSchema(_x, y) => {
{
let mut view_state = self.model.view_state.write().unwrap();
view_state.update_from_zoom(y as f32);
}
self.notify_view_state_changed();
},
KeyDown(event) => {
#[allow(non_upper_case_globals)]
use gdk::enums::key::{ r };
let mut schema = self.model.schema.write().unwrap();
let view_state = self.model.view_state.read().unwrap();
match event.get_keyval() {
r => {
view_state.hovered_component_uuid.as_ref().map(|uuid| schema.rotate_component(uuid.clone()));
},
_ => ()
}
}
}
}
fn notify_view_state_changed(&mut self) {
self.gl_area.queue_draw();
self.model.event_bus.get_handle().send(&EventMessage::ViewStateChanged);
let view_state = self.model.view_state.read().unwrap();
self.cursor_info.emit(cursor_info::Msg::ViewStateChanged(view_state.clone()));
}
fn make_context_current(&mut self, context: gdk::GLContext) {
// Make the GlContext received from GTK the current one
use gdk::GLContextExt;
context.make_current();
}
fn load_schema(schema_loader: &mut schema_loader::SchemaLoader, schema: Arc<RwLock<Schema>>, view_state: Arc<RwLock<ViewState>>, libraries: Arc<RwLock<ComponentLibraries>>) {
/*
* L O A D S C H E M A
*/
// Load library and schema file
let args: Vec<String> = env::args().collect();
// Load a schema form a file specified on the commandline
schema_loader.load_from_file(args[2].clone());
// Zoom to BB
let bb = schema.write().unwrap().get_bounding_box(&libraries.read().unwrap());
view_state.write().unwrap().update_from_box_pan(bb);
}
view! {
#[name="window"]
gtk::Window {
can_focus: false,
border_width: 1,
property_default_width: 1800,
property_default_height: 1000,
realize => Realize,
title: &self.model.title,
child: {
expand: true,
fill: true,
},
#[name="main_box"]
gtk::Box {
orientation: Vertical,
can_focus: false,
spacing: 6,
realize => Realize,
#[name="info_bar"]
InfoBar {
},
#[name="gl_area"]
gtk::GLArea {
can_focus: false,
hexpand: true,
vexpand: true,
realize => Realize,
unrealize => Unrealize,
resize(area, width, height) => Resize(width, height, area.get_scale_factor()),
render(area, context) => ({
let rgl = RenderGl(context.clone());
area.queue_render();
rgl
}, Inhibit(true)),
button_press_event(_, event) => ({
ButtonPressed(event.clone())
}, Inhibit(false)),
motion_notify_event(_, event) => (MoveCursor(event.clone()), Inhibit(false)),
scroll_event(_, event) => (ZoomOnSchema(
event.get_delta().0,
event.get_delta().1,
), Inhibit(false)),
},
#[name="cursor_info"]
CursorInfo {
},
},
key_press_event(_, event) => (KeyDown(event.clone()), Inhibit(false)),
delete_event(_, _) => (Quit, Inhibit(false)),
}
}
}