Unverified Commit 9e8211bd authored by Andrey Azov's avatar Andrey Azov Committed by GitHub
Browse files

Bootstrap setup, multiple genomes and zmenus in genome browser (#72)

A giant chunk of code pull request containing updates to genome browser and browser chrome
to enable browsing genomes of multiple species.
parent 6000200b
Pipeline #23854 passed with stages
in 4 minutes and 53 seconds
This diff is collapsed.
use composit::{
ActiveSource, Stick, Scale, ComponentSet, StateManager
ActiveSource, Stick, Scale, ComponentSet, StateManager, Stage
};
use model::driver::PrinterManager;
use model::driver::{ PrinterManager, Printer };
use model::train::{ Train, TrainManager, TravellerCreator };
use drivers::zmenu::{ ZMenuRegistry, ZMenuLeafSet };
use controller::global::AppRunner;
use controller::input::Action;
use controller::output::Report;
use data::{ Psychic, PsychicPacer, XferCache, XferClerk };
use types::DOWN;
use types::{ DOWN, Dot };
const MS_PER_UPDATE : f64 = 0.;
const MS_PRIME_DELAY: f64 = 2000.;
pub struct Compositor {
train_manager: TrainManager,
zmr: ZMenuRegistry,
bp_per_screen: f64,
updated: bool,
prime_delay: Option<f64>,
......@@ -32,6 +35,7 @@ impl Compositor {
pub fn new(printer: PrinterManager, xfercache: &XferCache, xferclerk: Box<XferClerk>) -> Compositor {
Compositor {
train_manager: TrainManager::new(&printer),
zmr: ZMenuRegistry::new(),
components: TravellerCreator::new(&printer),
bp_per_screen: 1.,
updated: true,
......@@ -46,6 +50,8 @@ impl Compositor {
}
}
pub fn get_zmr(&self) -> &ZMenuRegistry { &self.zmr }
pub fn get_prop_trans(&self) -> f32 { self.train_manager.get_prop_trans() }
fn prime_cache(&mut self, t: f64) {
......@@ -126,11 +132,22 @@ impl Compositor {
&mut self.wanted_componentset
}
fn add_component(&mut self, c: ActiveSource) {
pub fn redraw_where_needed(&mut self, printer: &mut Printer) {
let mut zmls = ZMenuLeafSet::new();
if let Some(train) = self.get_current_train() {
train.redraw_where_needed(printer,&mut zmls);
}
if let Some(train) = self.get_transition_train() {
train.redraw_where_needed(printer,&mut zmls);
}
self.zmr.add_leafset(zmls);
}
fn add_component(&mut self, mut c: ActiveSource) {
{
let cc = &mut self.components;
self.train_manager.each_train(|sc|
sc.add_component(cc,&c)
sc.add_component(cc,&mut c)
);
}
self.components.add_source(c);
......@@ -139,6 +156,10 @@ impl Compositor {
pub fn update_state(&mut self, oom: &StateManager) {
self.train_manager.update_state(oom);
}
pub fn intersects(&self, stage: &Stage, pos: Dot<i32,i32>) -> Vec<Action> {
self.zmr.intersects(stage,pos)
}
}
pub fn register_compositor_ticks(ar: &mut AppRunner) {
......
use std::fmt;
use composit::{ Stick, Scale };
use types::Placement;
#[derive(Clone,PartialEq,Eq,Hash)]
pub struct Leaf {
......@@ -53,6 +54,10 @@ impl Leaf {
(self.get_stick().get_name(),
format!("{}{}",self.scale.letter(),self.hindex))
}
pub fn fix_placement(&self, p: &Placement) -> Placement {
p.add_bp(self.get_start(),self.total_bp())
}
}
impl fmt::Debug for Leaf {
......
......@@ -5,7 +5,7 @@ mod combinedstickmanager;
mod componentset;
mod landscape;
mod leaf;
mod source;
pub mod source;
mod stage;
mod stick;
mod stickmanager;
......@@ -14,7 +14,7 @@ mod position;
mod wrapping;
pub use self::source::{
CombinedSource, Source, SourceResponseData, ActiveSource,
CombinedSource, Source, ActiveSource,
SourceManager, SourceManagerList, CombinedSourceManager
};
pub use self::combinedstickmanager::CombinedStickManager;
......
......@@ -67,19 +67,24 @@ impl Position {
self.pos.1 = self.pos.1.round();
}
pub fn middle_to_edge(&self, which: &Direction) -> f64 {
pub fn middle_to_edge(&self, which: &Direction, bump: bool) -> f64 {
let bp = self.get_screen_in_bp();
let (bump_min,bump_max) = if bump {
(self.px_to_bp(self.min_x_bumper),self.px_to_bp(self.max_x_bumper))
} else {
(0.,0.)
};
match *which {
LEFT => - bp/2. + self.px_to_bp(self.min_x_bumper),
RIGHT => bp/2. - self.px_to_bp(self.max_x_bumper),
LEFT => - bp/2. + bump_min,
RIGHT => bp/2. - bump_max,
UP => - self.screen_size.1 as f64/2.,
DOWN => self.screen_size.1 as f64/2.,
IN|OUT => 0.
}
}
pub fn get_edge(&self, which: &Direction) -> f64 {
let delta = self.middle_to_edge(which);
pub fn get_edge(&self, which: &Direction, bump: bool) -> f64 {
let delta = self.middle_to_edge(which,bump);
match *which {
LEFT|RIGHT => self.pos.0 + delta,
UP|DOWN => self.pos.1 + delta,
......@@ -88,7 +93,7 @@ impl Position {
}
pub fn get_limit_of_middle(&self, which: &Direction) -> f64 {
self.get_limit_of_edge(which) - self.middle_to_edge(which)
self.get_limit_of_edge(which) - self.middle_to_edge(which,true)
}
pub fn get_limit_of_edge(&self, which: &Direction) -> f64 {
......
......@@ -11,7 +11,9 @@ use composit::{
};
use model::driver::PrinterManager;
use model::train::{ Traveller, PartyResponses };
use drivers::zmenu::ZMenuRegistry;
use model::train::Traveller;
use composit::source::SourceResponse;
use super::SourcePart;
......@@ -21,16 +23,18 @@ pub struct ActiveSource {
lid: usize,
name: String,
parts: HashMap<Option<String>,SourcePart>,
source: Rc<Source>
source: Rc<Source>,
zmr: ZMenuRegistry
}
impl ActiveSource {
pub fn new(name: &str, source: Rc<Source>, als: &AllLandscapes, lid: usize) -> ActiveSource {
pub fn new(name: &str, source: Rc<Source>, zmr: &ZMenuRegistry, als: &AllLandscapes, lid: usize) -> ActiveSource {
ActiveSource {
source, lid,
name: name.to_string(),
als: als.clone(),
parts: HashMap::<Option<String>,SourcePart>::new()
parts: HashMap::<Option<String>,SourcePart>::new(),
zmr: zmr.clone()
}
}
......@@ -44,24 +48,23 @@ impl ActiveSource {
self.parts.keys().filter(|x| x.is_some()).map(|x| x.as_ref().unwrap().clone()).collect()
}
fn make_traveller(&self, pm: &PrinterManager, party: &PartyResponses, part: &Option<String>, leaf: &Leaf) -> Traveller {
let srr = party.get_srr(part);
Traveller::new(pm,self.clone(),part,leaf,srr)
fn make_one_traveller(&self, part: &Option<String>, leaf: &Leaf) -> Traveller {
Traveller::new(self.clone(),part,leaf)
}
pub fn make_party(&self, pm: &PrinterManager, party: &PartyResponses, leaf: &Leaf) -> Vec<Traveller> {
pub fn make_travellers(&mut self, leaf: &Leaf) -> Vec<Traveller> {
let mut out = Vec::<Traveller>::new();
out.push(self.make_traveller(pm,&party,&None,&leaf));
/* create the travellers */
out.push(self.make_one_traveller(&None,&leaf));
for part in self.list_parts() {
debug!("redraw","make_carriages {:?} for {}",leaf,part);
out.push(self.make_traveller(pm,&party,&Some(part),&leaf));
out.push(self.make_one_traveller(&Some(part),&leaf));
}
out
}
pub fn populate(&mut self, resp: PartyResponses, leaf: &Leaf) {
pub fn request_data(&self, party: SourceResponse, leaf: &Leaf) {
let twin = self.source.clone();
twin.populate(self,resp,leaf);
twin.request_data(self,party,leaf);
}
pub fn get_name(&self) -> &str { &self.name }
......@@ -75,6 +78,11 @@ impl ActiveSource {
self.als.with(lid,cb)
}
pub fn with_zmr<F,G>(&mut self, cb: F) -> G
where F: FnOnce(&mut ZMenuRegistry) -> G {
cb(&mut self.zmr)
}
pub fn all_landscapes<F,G>(&mut self, cb: F) -> Vec<Option<G>>
where F: Fn(usize,&mut Landscape) -> G {
self.als.every(cb)
......
......@@ -7,7 +7,8 @@ use composit::{
};
use data::{ BackendConfig, HttpXferClerk };
use debug::{ add_debug_sources };
use model::train::PartyResponses;
use drivers::zmenu::ZMenuRegistry;
use composit::source::SourceResponse;
use tácode::{ Tácode, TáSource };
const TOP : i32 = 50;
......@@ -38,17 +39,17 @@ impl CombinedSource {
}
impl Source for CombinedSource {
fn populate(&self, acs: &ActiveSource, lc: PartyResponses, leaf: &Leaf) {
fn request_data(&self, acs: &ActiveSource, lc: SourceResponse, leaf: &Leaf) {
let stick_name = leaf.get_stick().get_name();
if let Some(source) = self.per_stick_sources.get(&stick_name) {
source.populate(acs,lc,leaf);
source.request_data(acs,lc,leaf);
} else {
self.backend_source.populate(acs,lc,leaf);
self.backend_source.request_data(acs,lc,leaf);
}
}
}
pub fn build_combined_source(tc: &Tácode, config: &BackendConfig, als: &mut AllLandscapes, xf: &HttpXferClerk, type_name: &str) -> Option<ActiveSource> {
pub fn build_combined_source(tc: &Tácode, config: &BackendConfig, zmr: &ZMenuRegistry, als: &mut AllLandscapes, xf: &HttpXferClerk, type_name: &str) -> Option<ActiveSource> {
let lid = als.allocate(type_name);
let cfg_track = config.get_track(type_name);
let y_pos = cfg_track.map(|t| t.get_position()).unwrap_or(-1);
......@@ -58,7 +59,7 @@ pub fn build_combined_source(tc: &Tácode, config: &BackendConfig, als: &mut All
let backend = TáSource::new(tc,Box::new(xf.clone()),type_name,lid,config);
let mut combined = CombinedSource::new(Box::new(backend));
add_debug_sources(&mut combined,type_name);
let mut act = ActiveSource::new(type_name,Rc::new(combined),als,lid);
let mut act = ActiveSource::new(type_name,Rc::new(combined),zmr,als,lid);
act.new_part(None,Rc::new(StateAtom::new(&type_name)));
let none = vec!{};
let parts = cfg_track.map(|t| t.get_parts()).unwrap_or(&none);
......
......@@ -6,6 +6,7 @@ use std::collections::HashMap;
use composit::{ ActiveSource, AllLandscapes, SourceManager };
use data::{ BackendConfig, HttpXferClerk };
use drivers::zmenu::ZMenuRegistry;
use tácode::Tácode;
use super::build_combined_source;
......@@ -14,13 +15,15 @@ pub struct CombinedSourceManager {
sources: HashMap<String,Option<ActiveSource>>,
config: BackendConfig,
als: AllLandscapes,
xf: HttpXferClerk
xf: HttpXferClerk,
zmr: ZMenuRegistry
}
impl CombinedSourceManager {
pub fn new(tc: &Tácode, config: &BackendConfig,
pub fn new(tc: &Tácode, config: &BackendConfig, zmr: &ZMenuRegistry,
als: &AllLandscapes, xf: &HttpXferClerk) -> CombinedSourceManager {
CombinedSourceManager {
zmr: zmr.clone(),
tc: tc.clone(),
config: config.clone(),
als: als.clone(),
......@@ -34,7 +37,7 @@ impl SourceManager for CombinedSourceManager {
fn get_component(&mut self, name: &str) -> Option<ActiveSource> {
if !self.sources.contains_key(name) {
let tc = self.tc.clone();
let source = build_combined_source(&tc,&self.config,&mut self.als,&self.xf,name);
let source = build_combined_source(&tc,&self.config,&self.zmr,&mut self.als,&self.xf,name);
self.sources.insert(name.to_string(),source);
}
self.sources[name].clone()
......
......@@ -5,7 +5,7 @@ mod source;
mod sourcemanager;
mod sourcemanagerlist;
mod sourcepart;
mod sourceresponsedata;
mod sourceresponse;
pub use self::activesource::ActiveSource;
pub use self::combinedsource::{ CombinedSource, build_combined_source };
......@@ -14,4 +14,4 @@ pub use self::source::Source;
pub use self::sourcemanager::SourceManager;
pub use self::sourcemanagerlist::SourceManagerList;
pub use self::sourcepart::SourcePart;
pub use self::sourceresponsedata::SourceResponseData;
pub use self::sourceresponse::SourceResponse;
use composit::{ Leaf, ActiveSource };
use model::train::PartyResponses;
use composit::source::SourceResponse;
pub trait Source {
fn populate(&self, acs: &ActiveSource, lc: PartyResponses, leaf: &Leaf);
fn request_data(&self, acs: &ActiveSource, lc: SourceResponse, leaf: &Leaf);
}
use std::collections::HashMap;
use drivers::zmenu::ZMenuLeaf;
use model::driver::{ Printer, PrinterManager };
use model::train::{ Traveller, TravellerResponse, TravellerResponseData };
use composit::Leaf;
pub struct SourceResponse {
leaf: Leaf,
travellers: HashMap<Option<String>,Traveller>
}
impl SourceResponse {
pub fn new(pm: &mut PrinterManager, leaf: &Leaf, tt: &mut Vec<Traveller>) -> SourceResponse {
let mut travs = HashMap::new();
for t in tt.iter() {
travs.insert(t.get_part().clone(),t.clone());
}
let mut out = SourceResponse {
leaf: leaf.clone(),
travellers: travs
};
for t in tt {
t.set_visuals(pm.make_traveller_response(&leaf));
}
out
}
pub fn update_zml<F>(&mut self, part: &Option<String>, cb: F) where F: FnOnce(&mut ZMenuLeaf) {
self.travellers.get_mut(part).unwrap().update_zml(cb);
}
pub fn update_data<F>(&mut self, part: &Option<String>, cb: F) where F: FnOnce(&mut TravellerResponseData) {
self.travellers.get_mut(part).unwrap().update_data(cb);
}
pub fn done(&mut self) {
for (_,t) in &mut self.travellers {
t.set_response();
}
}
}
......@@ -2,10 +2,10 @@ use std::collections::HashMap;
use composit::{ Leaf, Position, Wrapping };
use controller::output::{ Report, ViewportReport };
use program::UniformValue;
use drivers::webgl::program::UniformValue;
use types::{
CPixel, cpixel, Move, Dot, Direction,
LEFT, RIGHT, UP, DOWN, IN, OUT
CPixel, Move, Dot, Direction,
LEFT, RIGHT, UP, DOWN, IN, OUT, XPosition, YPosition, Placement
};
// XXX TODO avoid big-minus-big type calculations which accumulate error
......@@ -31,11 +31,11 @@ impl Stage {
fn bumped(&self, direction: &Direction) -> bool {
let mul : f64 = direction.1.into();
self.pos.get_edge(direction).floor() * mul >= self.pos.get_limit_of_edge(direction).floor() * mul
self.pos.get_edge(direction,true).floor() * mul >= self.pos.get_limit_of_edge(direction).floor() * mul
}
pub fn update_report(&self, report: &Report) {
let (left,right) = (self.pos.get_edge(&LEFT),self.pos.get_edge(&RIGHT));
let (left,right) = (self.pos.get_edge(&LEFT,true),self.pos.get_edge(&RIGHT,true));
report.set_status("start",&left.floor().to_string());
report.set_status("end",&right.ceil().to_string());
report.set_status_bool("bumper-left",self.bumped(&LEFT));
......@@ -47,7 +47,7 @@ impl Stage {
}
pub fn update_viewport_report(&self, report: &ViewportReport) {
report.set_delta_y(-self.pos.get_edge(&UP) as i32);
report.set_delta_y(-self.pos.get_edge(&UP,false) as i32);
}
pub fn set_wrapping(&mut self, w: &Wrapping) {
......@@ -137,7 +137,7 @@ impl Stage {
let leaf_per_screen = bp_per_screen as f64 / bp_per_leaf;
let middle_bp = self.pos.get_middle();
let middle_leaf = middle_bp.0/bp_per_leaf; // including fraction of leaf
let current_leaf_left = (leaf.get_index() as f64);
let current_leaf_left = leaf.get_index() as f64;
hashmap! {
"uOpacity" => UniformValue::Float(opacity),
"uStageHpos" => UniformValue::Float((middle_leaf - current_leaf_left) as f32),
......@@ -148,4 +148,49 @@ impl Stage {
self.dims.1 as f32/2.)
}
}
pub fn intersects(&self, pos: Dot<i32,i32>, area: &Placement) -> bool {
let screen_bp = self.get_screen_in_bp();
let screen_px = self.dims;
let bp_px = screen_bp / screen_px.0;
let left_bp = self.pos.get_edge(&LEFT,false);
let top_px = self.pos.get_edge(&UP,false);
match area {
Placement::Stretch(r) => {
let pos_bp = left_bp + pos.0 as f64 * bp_px;
let nw = r.offset();
let se = r.far_offset();
bb_log!("zmenu","Q {:?}<={:?}[{:?}+{:?}*{:?}]<={:?} {:?}<={:?}<={:?}",
nw.0,pos_bp,left_bp,pos.0,bp_px,se.0,
nw.1,pos.1+top_px as i32,se.1);
nw.0 as f64 <= pos_bp && se.0 as f64 >= pos_bp &&
nw.1 <= pos.1+top_px as i32 && se.1 >= pos.1+top_px as i32
},
Placement::Placed(x,y) => {
let (x0,x1) = match x {
XPosition::Base(bp,s,e) => {
let px = (bp-left_bp) / bp_px;
(px+*s as f64,px+*e as f64)
},
XPosition::Pixel(s,e) => {
(s.min_dist(screen_px.0 as i32) as f64,
e.min_dist(screen_px.0 as i32) as f64)
}
};
let (y0,y1) = match y {
YPosition::Page(s,e) => {
(*s as f64-top_px, *e as f64-top_px)
}
YPosition::Pixel(s,e) => {
(s.min_dist(screen_px.1 as i32) as f64,
e.min_dist(screen_px.1 as i32) as f64)
}
};
bb_log!("zmenu","P {:?}<={:?}<={:?} {:?}<={:?}<={:?}",
x0,pos.0,x1, y0,pos.1,y1);
x0 <= pos.0 as f64 && x1 >= pos.0 as f64 &&
y0 <= pos.1 as f64 && y1 >= pos.1 as f64
}
}
}
}
......@@ -11,7 +11,7 @@ use composit::{
};
use controller::input::{ Action, actions_run, startup_actions };
use controller::global::{ AppRunnerWeak, AppRunner };
use controller::output::{ Report, ViewportReport };
use controller::output::{ Report, ViewportReport, ZMenuReports };
use data::{ BackendConfig, BackendStickManager, HttpManager, HttpXferClerk, XferCache };
use debug::add_debug_sticks;
use dom::domutil;
......@@ -34,6 +34,7 @@ pub struct App {
sticks: Box<StickManager>,
report: Option<Report>,
viewport: Option<ViewportReport>,
zmenu_reports: Option<ZMenuReports>,
csl: SourceManagerList,
http_clerk: HttpXferClerk,
als: AllLandscapes,
......@@ -43,10 +44,8 @@ pub struct App {
}
impl App {
pub fn new(tc: &Tácode, config: &BackendConfig, http_manager: &HttpManager, browser_el: &HtmlElement, config_url: &Url, outer_el: &HtmlElement) -> App {
pub fn new(tc: &Tácode, config: &BackendConfig, http_manager: &HttpManager, browser_el: &HtmlElement, config_url: &Url) -> App {
let browser_el = browser_el.clone();
let bottle_el = domutil::query_selector2(&outer_el.clone().into(),".bottle");
let swarm_el = domutil::query_selector2(&outer_el.clone().into(),".swarm");
domutil::inner_html(&browser_el.clone().into(),CANVAS);
let canv_el : HtmlElement = domutil::query_selector(&browser_el.clone().into(),"canvas").try_into().unwrap();
let bsm = BackendStickManager::new(config);
......@@ -66,6 +65,7 @@ impl App {
sticks: Box::new(csm),
report: None,
viewport: None,
zmenu_reports: None,
csl: SourceManagerList::new(),
http_clerk: clerk,
als: AllLandscapes::new(),
......@@ -73,7 +73,10 @@ impl App {
stage_resize: None,
last_resize_at: None
};
let dsm = CombinedSourceManager::new(&tc,config,&out.als,&out.http_clerk);
let dsm = {
let compo = &out.compo.lock().unwrap();
CombinedSourceManager::new(&tc,config,&compo.get_zmr(),&out.als,&out.http_clerk)
};
out.csl.add_compsource(Box::new(dsm));
out.run_actions(&startup_actions());
out
......@@ -114,6 +117,14 @@ impl App {
self.viewport = Some(report);
}
pub fn set_zmenu_reports(&mut self, report: ZMenuReports) {
self.zmenu_reports = Some(report);
}
pub fn get_zmenu_reports(&mut self) -> Option<&mut ZMenuReports> {
self.zmenu_reports.as_mut()
}
pub fn with_apprunner<F,G>(&mut self, cb:F) -> Option<G>
where F: FnOnce(&mut AppRunner) -> G {
self.ar.upgrade().as_mut().map(cb)
......@@ -180,7 +191,11 @@ impl App {
}
}
}
pub fn check_gone(self: &mut App) -> bool {
!domutil::in_page(&self.canv_el)
}
pub fn force_size(self: &mut App, sz: Dot<f64,f64>) {
self.stage_resize = Some(sz);
let mut stage = self.stage.lock().unwrap();
......
......@@ -9,7 +9,7 @@ use controller::scheduler::{ Scheduler, SchedRun, SchedulerGroup };
use controller::input::{
register_direct_events, register_user_events, register_dom_events
};
use controller::output::{ OutputAction, Report, ViewportReport };
use controller::output::{ OutputAction, Report, ViewportReport, ZMenuReports };
#[cfg(any(not(deploy),console))]
use data::blackbox::{
......@@ -23,8 +23,6 @@ use dom::event::EventControl;
use dom::domutil::browser_time;
use tácode::Tácode;
const SIZE_CHECK_INTERVAL_MS: f64 = 500.;
struct AppRunnerImpl {
g: GlobalWeak,