// Copyright 2015 Matthew Collins // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. ui_element!(Formatted { val: format::Component, width: f64, height: f64, scale_x: f64, scale_y: f64, text: Vec, max_width: f64, lines: usize }); impl Formatted { base_impl!(); pub fn new(renderer: &mut render::Renderer, val: format::Component, x: f64, y: f64) -> Formatted { let mut f = ui_create!(Formatted { val: val, x: x, y: y, width: 0.0, height: 18.0, scale_x: 1.0, scale_y: 1.0, text: Vec::new(), max_width: -1.0, lines: 0, }); f.init_component(renderer); f } pub fn with_width_limit(renderer: &mut render::Renderer, val: format::Component, x: f64, y: f64, max_width: f64) -> Formatted { let mut f = ui_create!(Formatted { val: val, x: x, y: y, width: 0.0, height: 18.0, scale_x: 1.0, scale_y: 1.0, text: Vec::new(), max_width: max_width, lines: 0, }); f.init_component(renderer); f } pub fn set_component(&mut self, renderer: &mut render::Renderer, val: format::Component) { self.val = val; self.init_component(renderer); } fn init_component(&mut self, renderer: &mut render::Renderer) { self.text.clear(); let mut state = FormatState { lines: 0, width: 0.0, offset: 0.0, text: Vec::new(), max_width: self.max_width, renderer: &renderer, }; state.build(&self.val, format::Color::White); self.height = (state.lines + 1) as f64 * 18.0; self.width = state.width; self.lines = state.lines; self.text = state.text; self.dirty = true; } fn update(&mut self, renderer: &mut render::Renderer) { self.init_component(renderer); } fn draw(&mut self, renderer: &mut render::Renderer, r: &Region, width: f64, height: f64, delta: f64) -> &Vec { if self.dirty { self.dirty = false; self.data.clear(); let sx = r.w / self.width; let sy = r.h / self.height; for e in &mut self.text { let reg = Container::get_draw_region_raw(e, sx, sy, r); e.set_dirty(true); self.data.extend(e.draw(renderer, ®, width, height, delta)); } } &self.data } pub fn get_size(&self) -> (f64, f64) { ((self.width + 2.0) * self.scale_x, self.height * self.scale_y) } lazy_field!(width, f64, get_width, set_width); lazy_field!(height, f64, get_height, set_height); lazy_field!(scale_x, f64, get_scale_x, set_scale_x); lazy_field!(scale_y, f64, get_scale_y, set_scale_y); } impl UIElement for Formatted { fn wrap(self) -> Element { Element::Formatted(self) } fn unwrap_ref<'a>(e: &'a Element) -> &'a Formatted { match e { &Element::Formatted(ref val) => val, _ => panic!("Incorrect type"), } } fn unwrap_ref_mut<'a>(e: &'a mut Element) -> &'a mut Formatted { match e { &mut Element::Formatted(ref mut val) => val, _ => panic!("Incorrect type"), } } } struct FormatState<'a> { max_width: f64, lines: usize, offset: f64, width: f64, text: Vec, renderer: &'a render::Renderer, } impl <'a> FormatState<'a> { fn build(&mut self, c: &format::Component, color: format::Color) { match c { &format::Component::Text(ref txt) => { let col = FormatState::get_color(&txt.modifier, color); self.append_text(&txt.text, col); let modi = &txt.modifier; if let Some(ref extra) = modi.extra { for e in extra { self.build(e, col); } } } } } fn append_text(&mut self, txt: &str, color: format::Color) { let mut width = 0.0; let mut last = 0; for (i, c) in txt.char_indices() { let size = self.renderer.ui.size_of_char(c) + 2.0; if (self.max_width > 0.0 && self.offset + width + size > self.max_width) || c == '\n' { let (rr, gg, bb) = color.to_rgb(); let text = Text::new(self.renderer, &txt[last..i], self.offset, (self.lines * 18 + 1) as f64, rr, gg, bb); self.text.push(text.wrap()); last = i; if c == '\n' { last += 1; } self.offset = 0.0; self.lines += 1; width = 0.0; } width += size; if self.offset + width > self.width { self.width = self.offset + width; } } if last != txt.len() { let (rr, gg, bb) = color.to_rgb(); let text = Text::new(self.renderer, &txt[last..], self.offset, (self.lines * 18 + 1) as f64, rr, gg, bb); self.offset += text.width + 4.0; // TODO Why is this 4 not 2? self.text.push(text.wrap()); if self.offset > self.width { self.width = self.offset; } } } fn get_color(modi: &format::Modifier, color: format::Color) -> format::Color { modi.color.unwrap_or(color) } }