//#![windows_subsystem = "windows"] #[macro_use] extern crate sciter; use sciter::dom::event::{MethodParams, DRAW_EVENTS, EVENT_GROUPS}; use sciter::dom::{Element, HELEMENT}; use sciter::graphics::{self, rgb, Graphics, HGFX}; use sciter::types::RECT; use sciter::Value; // 24:60:60, will be drawn as analog clock type Time = [u8; 3usize]; /// Clock native behavior. /// /// ## Behavior-specific HTML attributes: /// /// * `utc="integer"` - time zone offset, positive or negative. /// * `frozen` - time is not updated automtically. /// /// ## Value /// /// *read/write* Current time value in `HH::MM::SS` or `[HH, MM, SS]` form. /// /// ## Events /// /// N/A - this element does not generate any specific events. /// #[derive(Default)] struct Clock { element: Option, now: Time, gmt: i8, is_frozen: bool, } impl sciter::EventHandler for Clock { /// Claim what kind of events we want to receive. fn get_subscription(&mut self) -> Option { // we need timer and draw events // also behavior method calls Some(EVENT_GROUPS::HANDLE_TIMER | EVENT_GROUPS::HANDLE_DRAW | EVENT_GROUPS::HANDLE_METHOD_CALL ) } /// Our element is constructed. But scripts in HTML are not loaded yet. fn attached(&mut self, root: HELEMENT) { self.element = Some(Element::from(root)); let me = self.element.as_ref().unwrap(); // get attributes to initialize our clock if let Some(attr) = me.get_attribute("utc") { if let Ok(v) = attr.parse::() { self.gmt = v; } } // we don't update frozen clocks if let Some(_attr) = me.get_attribute("frozen") { self.is_frozen = true; } // timer to redraw our clock if !self.is_frozen { me.start_timer(300, 1).expect("Can't set timer"); } } /// Our behavior methods. fn on_method_call(&mut self, _root: HELEMENT, params: MethodParams) -> bool { match params { MethodParams::GetValue(retval) => { // engine wants out current value (e.g. `current = element.value`) let v: Value = self.now.iter().map(|v| i32::from(*v)).collect(); println!("return current time as {:?}", v); *retval = v; } MethodParams::SetValue(v) => { // engine sets our value (e.g. `element.value = new`) println!("set current time from {:?}", v); // "10:20:30" if v.is_string() { let s = v.as_string().unwrap(); let t = s.split(':').take(3).map(|n| n.parse::()); let mut new_time = Time::default(); for (i, n) in t.enumerate() { if let Err(_) = n { eprintln!("clock::set_value({:?}) is invalid", v); return true; // consume this event anyway } new_time[i] = n.unwrap(); } // use it as a new time self.set_time(new_time); // [10, 20, 30] } else if v.is_varray() { let mut new_time = Time::default(); for (i, n) in v.values().take(3).map(|n| n.to_int()).enumerate() { if n.is_none() { eprintln!("clock::set_value({:?}) is invalid", v); return true; } new_time[i] = n.unwrap() as u8 } // use it as a new time self.set_time(new_time); } else { // unknown format eprintln!("clock::set_value({:?}) is unsupported", v); return true; } } _ => { // unsupported event, skip it return false; } } // mark this event as handled (consume it) return true; } /// Redraw our element on each tick. fn on_timer(&mut self, root: HELEMENT, _timer_id: u64) -> bool { if self.update_time() { // redraw our clock Element::from(root).refresh().expect("Can't refresh element"); } true } /// Request to draw our element. fn on_draw(&mut self, _root: HELEMENT, gfx: HGFX, area: &RECT, layer: DRAW_EVENTS) -> bool { if layer == DRAW_EVENTS::DRAW_CONTENT { // draw content only // leave the back- and foreground to be default let mut gfx = Graphics::from(gfx); self .draw_clock(&mut gfx, &area) .map_err(|e| println!("error in draw_clock: {:?}", e) ) .ok(); } // allow default drawing anyway return false; } } // 360° const PI2: f32 = 2.0 * std::f32::consts::PI; impl Clock { /// Update current time and say if changed. fn update_time(&mut self) -> bool { if self.is_frozen { return false; } // ask our script for the current time if let Some(now) = self.get_time() { let update = self.now != now; self.now = now; update } else { false } } /// Set the new time and redraw our element. fn set_time(&mut self, new_time: Time) { // set new time and redraw our clock self.now = new_time; if let Some(el) = self.element.as_ref() { el.refresh().ok(); } } /// Get current time from script. fn get_time(&self) -> Option