mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
move rust-sciter in
This commit is contained in:
BIN
libs/rust-sciter/examples/archived.rc
Normal file
BIN
libs/rust-sciter/examples/archived.rc
Normal file
Binary file not shown.
17
libs/rust-sciter/examples/archived.rs
Normal file
17
libs/rust-sciter/examples/archived.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
//! Sciter sample with archived resources.
|
||||
|
||||
extern crate sciter;
|
||||
|
||||
fn main() {
|
||||
let resources = include_bytes!("archived.rc");
|
||||
|
||||
let mut frame = sciter::WindowBuilder::main_window()
|
||||
.fixed()
|
||||
.with_size((600, 400))
|
||||
.create();
|
||||
|
||||
frame.archive_handler(resources).expect("Invalid archive");
|
||||
|
||||
frame.load_file("this://app/index.htm");
|
||||
frame.run_app();
|
||||
}
|
||||
162
libs/rust-sciter/examples/clock.htm
Normal file
162
libs/rust-sciter/examples/clock.htm
Normal file
@@ -0,0 +1,162 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Clock</title>
|
||||
<style>
|
||||
body { padding: 5dip; }
|
||||
|
||||
#clocks {
|
||||
size: *;
|
||||
flow: horizontal-flow;
|
||||
}
|
||||
|
||||
.city {
|
||||
flow: vertical;
|
||||
size: *;
|
||||
}
|
||||
|
||||
.city > caption {
|
||||
width: *;
|
||||
padding: 5dip;
|
||||
flow:horizontal;
|
||||
horizontal-align: center;
|
||||
font-size: 11pt;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.city > clock, .edit {
|
||||
margin-right: *;
|
||||
margin-left: *;
|
||||
margin-bottom: 5dip;
|
||||
}
|
||||
|
||||
.city > .edit {
|
||||
flow: horizontal;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
clock {
|
||||
behavior: native-clock;
|
||||
display: block;
|
||||
min-width: 150dip;
|
||||
min-height: 150dip;
|
||||
}
|
||||
|
||||
.native-text {
|
||||
behavior: native-text;
|
||||
display: block;
|
||||
min-height: 100dip;
|
||||
min-width: 100dip;
|
||||
outline: 1px solid orange;
|
||||
}
|
||||
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
|
||||
// called from Rust
|
||||
function getLocalTime() {
|
||||
var d = new Date();
|
||||
return [d.hour, d.minute, d.second];
|
||||
}
|
||||
|
||||
function getUtcTime(offset) {
|
||||
var d = new Date();
|
||||
d.UTChour += offset;
|
||||
return [d.UTChour, d.UTCminute, d.UTCsecond];
|
||||
}
|
||||
|
||||
var timeSet = $(#set-time);
|
||||
var timeEdit = $(#edit-time);
|
||||
var timeShow = $(#show-time);
|
||||
|
||||
timeEdit << event change {
|
||||
var now = this.value;
|
||||
var local = [now.hour, now.minute, now.second];
|
||||
stdout.printf("timeEdit: %v %v\n", now, local);
|
||||
timeShow.value = local;
|
||||
}
|
||||
|
||||
timeSet << event click {
|
||||
var now = new Date();
|
||||
var local = [now.hour, now.minute, now.second];
|
||||
stdout.printf("timeSet: %v %v\n", now, local);
|
||||
timeEdit.value = now;
|
||||
timeShow.value = local;
|
||||
}
|
||||
|
||||
function self.ready() {
|
||||
var now = new Date();
|
||||
var local = [now.hour, now.minute, now.second];
|
||||
stdout.printf("initial time: %v %v\n", now, local);
|
||||
timeShow.value = local;
|
||||
}
|
||||
|
||||
// update window icon
|
||||
function setIcon() {
|
||||
var clock = $(clock);
|
||||
|
||||
// get clock element size
|
||||
var (w, h) = clock.box(#dimension, #border);
|
||||
if (w == 0 || h == 0)
|
||||
return;
|
||||
|
||||
// make a snapshot of it with 32x32 size
|
||||
var img = new Image(clock, w, h, 32, 32);
|
||||
var png = img.toBytes();
|
||||
img.destroy();
|
||||
|
||||
// make an icon from the snapshot
|
||||
var icon = Image.fromBytes(png);
|
||||
view.windowIcon = icon;
|
||||
|
||||
return true; // continue to update icon ;)
|
||||
}
|
||||
self.timer(1000, setIcon);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="clocks" some>
|
||||
<div class="city">
|
||||
<caption>London</caption>
|
||||
<clock utc="0" title="UTC+0"></clock>
|
||||
</div>
|
||||
|
||||
<div class="city">
|
||||
<caption>Tokyo</caption>
|
||||
<clock utc="+9" title="UTC+9"></clock>
|
||||
</div>
|
||||
|
||||
<div class="city">
|
||||
<caption>New York</caption>
|
||||
<clock utc="-4" title="UTC-4"></clock>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="local" some>
|
||||
<div class="city">
|
||||
<caption>Frozen time</caption>
|
||||
<clock frozen id="show-time"></clock>
|
||||
<div class="edit">
|
||||
<widget type="time" value="now" id="edit-time" title="Change time of the drawn clock" />
|
||||
<widget type="button" id="set-time" title="Reset back to local time">=</widget>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="city">
|
||||
<caption>Text</caption>
|
||||
<div class="native-text">static text</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
368
libs/rust-sciter/examples/clock.rs
Normal file
368
libs/rust-sciter/examples/clock.rs
Normal file
@@ -0,0 +1,368 @@
|
||||
//#![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<Element>,
|
||||
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<EVENT_GROUPS> {
|
||||
// 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::<i8>() {
|
||||
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::<u8>());
|
||||
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<Time> {
|
||||
let el = self.element.as_ref().unwrap();
|
||||
let script_func = if self.is_frozen { "getLocalTime" } else { "getUtcTime" };
|
||||
if let Ok(time) = el.call_function(script_func, &make_args!(self.gmt as i32)) {
|
||||
assert_eq!(time.len(), 3);
|
||||
let mut now = Time::default();
|
||||
for (i, n) in time.values().take(3).map(|n| n.to_int()).enumerate() {
|
||||
now[i] = n.unwrap() as u8;
|
||||
}
|
||||
Some(now)
|
||||
} else {
|
||||
eprintln!("error: can't eval get time script");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw our element.
|
||||
fn draw_clock(&mut self, gfx: &mut Graphics, area: &RECT) -> graphics::Result<()> {
|
||||
// save previous state
|
||||
let mut gfx = gfx.save_state()?;
|
||||
|
||||
// setup our attributes
|
||||
let left = area.left as f32;
|
||||
let top = area.top as f32;
|
||||
let width = area.width() as f32;
|
||||
let height = area.height() as f32;
|
||||
|
||||
let scale = if width < height { width / 300.0 } else { height / 300.0 };
|
||||
|
||||
// translate to its center and rotate 45° left.
|
||||
gfx
|
||||
.translate((left + width / 2.0, top + height / 2.0))?
|
||||
.scale((scale, scale))?
|
||||
.rotate(-PI2 / 4.)?;
|
||||
|
||||
gfx.line_color(0)?.line_cap(graphics::LINE_CAP::ROUND)?;
|
||||
|
||||
// draw clock background
|
||||
self.draw_outline(&mut *gfx)?;
|
||||
|
||||
// draw clock sticks
|
||||
self.draw_time(&mut *gfx)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Draw clock static area (hour/minute marks).
|
||||
fn draw_outline(&mut self, gfx: &mut Graphics) -> graphics::Result<()> {
|
||||
// hour marks (every 5 ticks)
|
||||
{
|
||||
let mut gfx = gfx.save_state()?;
|
||||
gfx.line_width(8.0)?.line_color(rgb(0x32, 0x5F, 0xA2))?;
|
||||
|
||||
for _ in 0..12 {
|
||||
gfx.rotate(PI2 / 12.)?.line((137., 0.), (144., 0.))?;
|
||||
}
|
||||
}
|
||||
|
||||
// minute marks (every but 5th tick)
|
||||
{
|
||||
let mut gfx = gfx.save_state()?;
|
||||
gfx.line_width(3.0)?.line_color(rgb(0xA5, 0x2A, 0x2A))?;
|
||||
|
||||
for i in 0..60 {
|
||||
if i % 5 != 0 {
|
||||
// skip hours
|
||||
gfx.line((143., 0.), (146., 0.))?;
|
||||
}
|
||||
gfx.rotate(PI2 / 60.)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Draw clock arrows.
|
||||
fn draw_time(&mut self, gfx: &mut Graphics) -> graphics::Result<()> {
|
||||
let time = &self.now;
|
||||
let hours = f32::from(time[0]);
|
||||
let minutes = f32::from(time[1]);
|
||||
let seconds = f32::from(time[2]);
|
||||
|
||||
{
|
||||
// hours
|
||||
let mut gfx = gfx.save_state()?;
|
||||
|
||||
// 2PI*/12, 2PI/720,
|
||||
gfx.rotate(hours * (PI2 / 12 as f32) + minutes * (PI2 / (12 * 60) as f32) + seconds * (PI2 / (12 * 60 * 60) as f32))?;
|
||||
|
||||
gfx
|
||||
.line_width(14.0)?
|
||||
.line_color(rgb(0x32, 0x5F, 0xA2))?
|
||||
.line((-20., 0.), (70., 0.))?;
|
||||
}
|
||||
{
|
||||
// minutes
|
||||
let mut gfx = gfx.save_state()?;
|
||||
|
||||
gfx.rotate(minutes * (PI2 / 60 as f32) + seconds * (PI2 / (60 * 60) as f32))?;
|
||||
|
||||
gfx
|
||||
.line_width(10.0)?
|
||||
.line_color(rgb(0x32, 0x5F, 0xA2))?
|
||||
.line((-28., 0.), (100., 0.))?;
|
||||
}
|
||||
{
|
||||
// seconds
|
||||
let mut gfx = gfx.save_state()?;
|
||||
|
||||
gfx.rotate(seconds * (PI2 / 60 as f32))?;
|
||||
|
||||
gfx
|
||||
.line_width(6.0)?
|
||||
.line_color(rgb(0xD4, 0, 0))?
|
||||
.fill_color(rgb(0xD4, 0, 0))?
|
||||
.line((-30., 0.), (83., 0.))?
|
||||
.circle((0., 0.), 10.)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
#[derive(Default)]
|
||||
struct Text;
|
||||
|
||||
impl sciter::EventHandler for Text {
|
||||
fn get_subscription(&mut self) -> Option<EVENT_GROUPS> {
|
||||
Some(EVENT_GROUPS::HANDLE_DRAW)
|
||||
}
|
||||
|
||||
fn attached(&mut self, _root: HELEMENT) {
|
||||
}
|
||||
|
||||
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);
|
||||
let e = Element::from(_root);
|
||||
self
|
||||
.draw_text(&e, &mut gfx, &area)
|
||||
.map_err(|e| println!("error in draw_clock: {:?}", e) )
|
||||
.ok();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// allow default drawing anyway
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl Text {
|
||||
fn draw_text(&mut self, e: &Element, gfx: &mut Graphics, area: &RECT) -> graphics::Result<()> {
|
||||
|
||||
// save previous state
|
||||
let mut gfx = gfx.save_state()?;
|
||||
|
||||
// setup our attributes
|
||||
// let left = area.left as f32;
|
||||
// let top = area.top as f32;
|
||||
// let width = area.width() as f32;
|
||||
// let height = area.height() as f32;
|
||||
|
||||
// println!("text::draw on {} at {} {} {} {}", e, left, top, width, height);
|
||||
|
||||
use sciter::graphics::Text;
|
||||
|
||||
let t = Text::with_style(&e, "native text", "font-style: italic")?;
|
||||
gfx.draw_text(&t, (area.left as f32, area.top as f32), 7)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut frame = sciter::WindowBuilder::main_window().with_size((800, 600)).create();
|
||||
frame.register_behavior("native-clock", || Box::new(Clock::default()));
|
||||
frame.register_behavior("native-text", || Box::new(Text::default()));
|
||||
frame.load_html(include_bytes!("clock.htm"), Some("example://clock.htm"));
|
||||
frame.run_app();
|
||||
}
|
||||
272
libs/rust-sciter/examples/dom.rs
Normal file
272
libs/rust-sciter/examples/dom.rs
Normal file
@@ -0,0 +1,272 @@
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unused_must_use)]
|
||||
|
||||
extern crate sciter;
|
||||
|
||||
use sciter::{Value, Element, HELEMENT};
|
||||
use sciter::dom::event::*;
|
||||
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct DocumentHandler;
|
||||
|
||||
impl sciter::EventHandler for DocumentHandler {
|
||||
|
||||
fn attached(&mut self, _root: sciter::HELEMENT) {
|
||||
println!("attached");
|
||||
}
|
||||
|
||||
fn detached(&mut self, root: sciter::HELEMENT) {
|
||||
let root = Element::from(root);
|
||||
println!("detaching from {}", root);
|
||||
}
|
||||
|
||||
fn document_complete(&mut self, root: sciter::HELEMENT, source: sciter::HELEMENT) {
|
||||
|
||||
println!("document is loaded.");
|
||||
|
||||
let root = Element::from(root);
|
||||
assert_eq!(root.get_tag(), "html");
|
||||
println!("root {:?}", root);
|
||||
|
||||
let head = root.first_child().expect("empty <html>?");
|
||||
assert_eq!(head.get_tag(), "head");
|
||||
assert_eq!(head.index(), 0);
|
||||
println!("head {:?}", head);
|
||||
|
||||
let body = head.next_sibling().expect("only <head>?");
|
||||
assert_eq!(body.get_tag(), "body");
|
||||
assert_eq!(body.index(), 1);
|
||||
println!("body {:?}", body);
|
||||
|
||||
assert_eq!(body.first_sibling().expect("must be head"), head);
|
||||
assert_eq!(body.last_sibling().expect("must be body"), body);
|
||||
|
||||
println!("for loop in children");
|
||||
for e in root.children() {
|
||||
println!("child {:?}", e);
|
||||
}
|
||||
|
||||
println!("for loop in ref");
|
||||
for e in &root {
|
||||
println!("child {:?}", e);
|
||||
}
|
||||
|
||||
if let Ok(Some(h1)) = body.find_first("body > h1") {
|
||||
println!("h1 {:?}", h1);
|
||||
|
||||
let h1_parent = h1.parent().expect("come on!");
|
||||
assert_eq!(h1_parent, body);
|
||||
|
||||
let text = h1.get_text();
|
||||
assert_eq!(text, "Herman Melville - Moby-Dick");
|
||||
|
||||
let html = h1.get_html(true);
|
||||
assert_eq!(html.as_slice(), br"<h1>Herman Melville - Moby-Dick</h1>".as_ref());
|
||||
|
||||
let value = h1.get_value();
|
||||
assert!(value.is_string());
|
||||
assert_eq!(value.as_string().unwrap(), text);
|
||||
}
|
||||
|
||||
if let Some(mut h1) = body.first_child() {
|
||||
println!("changing h1 attributes");
|
||||
h1.set_style_attribute("color", "green");
|
||||
h1.set_style_attribute("outline", "1px solid orange");
|
||||
h1.set_attribute("title", "yellow!");
|
||||
}
|
||||
|
||||
{
|
||||
let all: Vec<Element> = body.find_all("div > p").unwrap().expect("must be at least one 'div > p'");
|
||||
assert!(!all.is_empty());
|
||||
assert_eq!(all.len(), 1);
|
||||
all.len();
|
||||
}
|
||||
|
||||
if let Ok(Some(mut body)) = root.find_first("html > body") {
|
||||
let mut div = Element::with_parent("div", &mut body).unwrap();
|
||||
div.set_attribute("id", "requests");
|
||||
div.set_style_attribute("outline", "1px solid orange");
|
||||
div.set_style_attribute("margin", "10dip 0");
|
||||
div.set_style_attribute("padding", "4dip");
|
||||
|
||||
let e = Element::with_text("label", "Requests:").unwrap();
|
||||
div.append(&e).unwrap();
|
||||
|
||||
let d = Element::with_text("div", "data").unwrap();
|
||||
div.append(&d).unwrap();
|
||||
|
||||
let c = Element::with_text("div", "footer").unwrap();
|
||||
div.append(&c).unwrap();
|
||||
|
||||
d.request_html("https://sciter.com/test/text.txt", None).unwrap();
|
||||
|
||||
// d.send_get_request("https://sciter.com/test/text.txt", None).expect("can't send an http request");
|
||||
// d.send_get_request("http://httpbin.org/html", None).expect("can't send an http request");
|
||||
// d.send_get_request("http://httpbin.org/get?one=1&two=2", None).expect("can't send an http request");
|
||||
|
||||
// let params = [("one", "1"), ("two", "2")];
|
||||
// let method = sciter::request::REQUEST_TYPE::AsyncGet;
|
||||
// let data_type = sciter::request::RESOURCE_TYPE::HTML;
|
||||
// d.send_request("http://httpbin.org/html", Some(¶ms), Some(method), Some(data_type)).expect("can't send an http request");
|
||||
}
|
||||
|
||||
if let Ok(Some(mut body)) = root.find_first("html > body") {
|
||||
|
||||
println!("creating some elments");
|
||||
|
||||
// DOM manipulation.
|
||||
// After creating the new Element, we can set only attributes for it until we'll attach it to the DOM.
|
||||
//
|
||||
let mut div = Element::with_parent("div", &mut body).unwrap();
|
||||
div.set_style_attribute("outline", "1px solid orange");
|
||||
div.set_style_attribute("width", "max-content");
|
||||
div.set_style_attribute("padding", "5dip");
|
||||
|
||||
let mut lb = Element::with_text("label", "Output: ").unwrap();
|
||||
div.append(&lb).expect("wtf?"); // push as reference, we can access this `lb` still.
|
||||
|
||||
let mut date = Element::with_type("input", "date").unwrap();
|
||||
date.set_attribute("id", "mydate");
|
||||
date.set_attribute("value", "now");
|
||||
|
||||
lb.append(&date).expect("wtf?");
|
||||
|
||||
date.set_style_attribute("width", "100px");
|
||||
date.set_style_attribute("outline", "1px dotted gray");
|
||||
date.set_style_attribute("margin", "10px");
|
||||
|
||||
|
||||
lb.set_attribute("accesskey", "o");
|
||||
lb.set_style_attribute("color", "lightblue");
|
||||
lb.set_style_attribute("vertical-align", "middle");
|
||||
|
||||
let mut progress = Element::create("progress").unwrap();
|
||||
progress.set_attribute("max", "100");
|
||||
progress.set_attribute("id", "id1");
|
||||
progress.set_attribute("title", "Click to start timer.");
|
||||
|
||||
div.append(&progress).expect("wtf?");
|
||||
|
||||
// after attaching Element to DOM, we can set its styles, text, html or value.
|
||||
progress.set_value(Value::from(42));
|
||||
progress.set_style_attribute("behavior", "progress clickable");
|
||||
|
||||
// attach a new handler to this element;
|
||||
// since timers are not sinking/bubbling, we need to attach
|
||||
// a dedicated handler to that element directly.
|
||||
let handler = ProgressHandler::default();
|
||||
progress.attach_handler(handler).expect("can't attach?");
|
||||
|
||||
let mut e = Element::with_text("span", " <-- check tooltip").unwrap();
|
||||
div.append(&e);
|
||||
|
||||
e.set_style_attribute("font-style", "italic");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ProgressHandler {
|
||||
progress: Option<Element>,
|
||||
start_timer: bool,
|
||||
}
|
||||
|
||||
impl sciter::EventHandler for ProgressHandler {
|
||||
|
||||
fn get_subscription(&mut self) -> Option<EVENT_GROUPS> {
|
||||
Some(default_events() | EVENT_GROUPS::HANDLE_TIMER)
|
||||
}
|
||||
|
||||
fn attached(&mut self, root: sciter::HELEMENT) {
|
||||
let root = Element::from(root);
|
||||
println!("attached an element event handler to {}", root);
|
||||
if root.test("progress") {
|
||||
self.progress = Some(root.clone());
|
||||
self.start_timer = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn detached(&mut self, root: sciter::HELEMENT) {
|
||||
let root = Element::from(root);
|
||||
println!("detaching from {}", root);
|
||||
}
|
||||
|
||||
fn on_event(&mut self, root: HELEMENT, source: HELEMENT, target: HELEMENT, code: BEHAVIOR_EVENTS, phase: PHASE_MASK, reason: EventReason) -> bool {
|
||||
if phase != PHASE_MASK::BUBBLING {
|
||||
return false;
|
||||
}
|
||||
|
||||
match code {
|
||||
BEHAVIOR_EVENTS::BUTTON_CLICK => {
|
||||
|
||||
let source = Element::from(source);
|
||||
let mut target = Element::from(target);
|
||||
|
||||
println!("button click on target {}", target);
|
||||
|
||||
if self.progress.is_some() && *self.progress.as_ref().unwrap() == target {
|
||||
self.start_timer = !self.start_timer;
|
||||
|
||||
if self.start_timer {
|
||||
println!("starting timer");
|
||||
target.set_value(Value::from(0));
|
||||
target.start_timer(1000, 1).ok();
|
||||
} else {
|
||||
println!("stopping timer");
|
||||
target.stop_timer(1);
|
||||
|
||||
let cur = target.get_value();
|
||||
target.set_attribute("title", &format!("Current value is {}. Click to start the timer again.", cur));
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn on_timer(&mut self, root: HELEMENT, timer_id: u64) -> bool {
|
||||
println!("timer {} tick on {}", timer_id, Element::from(root));
|
||||
if timer_id == 1 && self.progress.is_some() {
|
||||
let e = self.progress.as_mut().unwrap();
|
||||
let max_attr = e.get_attribute("max").unwrap();
|
||||
let max: f64 = max_attr.parse().unwrap();
|
||||
|
||||
let v = e.get_value();
|
||||
let next = v.to_float().unwrap() + 5.0;
|
||||
|
||||
if next > max {
|
||||
println!("that's enough, finish.");
|
||||
self.start_timer = false;
|
||||
e.stop_timer(1);
|
||||
}
|
||||
|
||||
e.set_value(Value::from(next));
|
||||
e.set_attribute("title", &format!("Current value is {}. Click to stop the timer if need.", next));
|
||||
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut frame = sciter::WindowBuilder::main_window()
|
||||
.with_size((750, 950))
|
||||
.debug()
|
||||
.create();
|
||||
|
||||
println!("attaching an event handler for the whole window");
|
||||
frame.event_handler(DocumentHandler::default());
|
||||
frame.set_title("DOM sample");
|
||||
|
||||
println!("loading the page...");
|
||||
frame.load_file("http://httpbin.org/html");
|
||||
|
||||
println!("running the app");
|
||||
frame.run_app();
|
||||
}
|
||||
69
libs/rust-sciter/examples/download.rs
Normal file
69
libs/rust-sciter/examples/download.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
//! Download http content (Go sciter example port).
|
||||
#![allow(dead_code)]
|
||||
|
||||
extern crate sciter;
|
||||
|
||||
use sciter::dom::HELEMENT;
|
||||
use sciter::host;
|
||||
use sciter::utf;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
struct Handler {
|
||||
host: Weak<sciter::Host>,
|
||||
}
|
||||
|
||||
impl sciter::EventHandler for Handler {
|
||||
fn document_complete(&mut self, _root: HELEMENT, _target: HELEMENT) {
|
||||
if let Some(host) = self.host.upgrade() {
|
||||
// eval script inside the document to receive a "user@machine" string.
|
||||
let result = host.eval_script("[Sciter.userName(), Sciter.machineName(true)].join(`@`)");
|
||||
match result {
|
||||
Ok(name) => {
|
||||
println!("running on {}", name);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("error! {}", e.as_string().unwrap_or("?".to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sciter::HostHandler for Handler {
|
||||
fn on_data_loaded(&mut self, pnm: &host::SCN_DATA_LOADED) {
|
||||
println!("data loaded, uri: `{}`, {} bytes.", utf::w2s(pnm.uri), pnm.dataSize);
|
||||
}
|
||||
|
||||
fn on_attach_behavior(&mut self, pnm: &mut host::SCN_ATTACH_BEHAVIOR) -> bool {
|
||||
let el = sciter::Element::from(pnm.element);
|
||||
let name = utf::u2s(pnm.name);
|
||||
println!("{}: behavior {}", el, name);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Handler {
|
||||
fn drop(&mut self) {
|
||||
// called 2 times because it is created 2 times
|
||||
println!("Good bye, window");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut frame = sciter::WindowBuilder::main_window().with_size((1024, 768)).create();
|
||||
|
||||
// Can't use something like `frame.sciter_handler(Rc::new(handler))` yet.
|
||||
let handler = Handler {
|
||||
host: Rc::downgrade(&frame.get_host()),
|
||||
};
|
||||
frame.sciter_handler(handler);
|
||||
|
||||
let handler = Handler {
|
||||
host: Rc::downgrade(&frame.get_host()),
|
||||
};
|
||||
frame.event_handler(handler);
|
||||
|
||||
frame.set_title("Download sample");
|
||||
frame.load_file("http://httpbin.org/html");
|
||||
frame.run_app();
|
||||
}
|
||||
18
libs/rust-sciter/examples/extension.htm
Normal file
18
libs/rust-sciter/examples/extension.htm
Normal file
@@ -0,0 +1,18 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>extension test</title>
|
||||
<style type="text/css">
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
// copy "extension.dll" next to the "sciter.dll"
|
||||
const ext = include library "extension";
|
||||
debug: ext;
|
||||
debug: ext.add(1,2);
|
||||
debug: ext.sub(1,2);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h4>see logs in Inspector</h4>
|
||||
</body>
|
||||
</html>
|
||||
17
libs/rust-sciter/examples/extension/Cargo.toml
Normal file
17
libs/rust-sciter/examples/extension/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "extension"
|
||||
version = "0.1.0"
|
||||
description = "A simple Sciter extension library"
|
||||
authors = ["pravic <ehysta@gmail.com>"]
|
||||
homepage = "https://sciter.com/include-library-name-native-extensions/"
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
path = "src/extension.rs"
|
||||
crate-type = ["cdylib"]
|
||||
test = false
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
sciter-rs = { version = "0.5", path="../../", features = ["extension"] }
|
||||
50
libs/rust-sciter/examples/extension/src/extension.rs
Normal file
50
libs/rust-sciter/examples/extension/src/extension.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
//! Sciter extension library example.
|
||||
//!
|
||||
//! See the [blog post](https://sciter.com/include-library-name-native-extensions/).
|
||||
|
||||
#[macro_use]
|
||||
extern crate sciter;
|
||||
|
||||
use sciter::types::{BOOL, VALUE};
|
||||
use sciter::Value;
|
||||
|
||||
/// Extension entry point.
|
||||
#[no_mangle]
|
||||
pub extern "system" fn SciterLibraryInit(api: &'static sciter::ISciterAPI, exported: &mut VALUE) -> BOOL {
|
||||
sciter::set_host_api(api);
|
||||
|
||||
let ext_api = vmap! {
|
||||
"add" => add,
|
||||
"sub" => sub,
|
||||
};
|
||||
|
||||
ext_api.pack_to(exported);
|
||||
|
||||
true as BOOL
|
||||
}
|
||||
|
||||
/// Calculate the sum of all the given arguments.
|
||||
pub fn add(args: &[Value]) -> Value {
|
||||
let sum: i32 = args
|
||||
.iter()
|
||||
.map(|v| v.to_int())
|
||||
.filter(|v| v.is_some())
|
||||
.map(|v| v.unwrap())
|
||||
.sum();
|
||||
|
||||
sum.into()
|
||||
}
|
||||
|
||||
/// `function sub(a, b) { return a - b; }`
|
||||
pub fn sub(args: &[Value]) -> std::result::Result<Value, String> {
|
||||
if let [a, b] = args {
|
||||
let a = a.to_int().ok_or("`a` is not an int")?;
|
||||
let b = b.to_int().ok_or("`b` is not an int")?;
|
||||
|
||||
let result = a - b;
|
||||
|
||||
Ok(result.into())
|
||||
} else {
|
||||
Err(format!("sub(a,b) expects 2 parameters, given {} instead.", args.len()))
|
||||
}
|
||||
}
|
||||
50
libs/rust-sciter/examples/fire_event.htm
Normal file
50
libs/rust-sciter/examples/fire_event.htm
Normal file
@@ -0,0 +1,50 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Fire event demo</title>
|
||||
<style>
|
||||
|
||||
html {
|
||||
background: radial-gradient(75% 75%, circle farthest-side, white, orange, rgb(0, 0, 204));
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#message {
|
||||
margin: 10dip 0dip;
|
||||
padding: 5dip;
|
||||
width: 60%%;
|
||||
min-height: 60dip;
|
||||
|
||||
color: black;
|
||||
background: #ccc;
|
||||
outline: 1px solid orange;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
view.caption = $(head > title).value;
|
||||
|
||||
$(#machine).text = Sciter.machineName();
|
||||
|
||||
$(#post).on("click", : {
|
||||
$(#message).postEvent(Event.CHANGE, 0, this, "hello?");
|
||||
});
|
||||
|
||||
$(#message).on("change", function(e) {
|
||||
this.text = String.printf("Event from `%s`: %v\n", e.source.id, e.data);
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Fire event</h1>
|
||||
<p>Running on <em #machine/> machine</p>
|
||||
|
||||
<button id="post">Post event</button>
|
||||
<button id="send">Send event</button>
|
||||
<button id="fire">Fire event</button>
|
||||
|
||||
<div id="message"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
60
libs/rust-sciter/examples/fire_event.rs
Normal file
60
libs/rust-sciter/examples/fire_event.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
//! Fire event Sciter sample.
|
||||
#![allow(unused_variables)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
extern crate sciter;
|
||||
|
||||
use sciter::Element;
|
||||
use self::sciter::dom::event::*;
|
||||
use self::sciter::dom::HELEMENT;
|
||||
use self::sciter::value::Value;
|
||||
|
||||
struct FireEvent;
|
||||
|
||||
impl sciter::EventHandler for FireEvent {
|
||||
|
||||
fn on_event(&mut self, root: HELEMENT, source: HELEMENT, target: HELEMENT, code: BEHAVIOR_EVENTS, phase: PHASE_MASK, reason: EventReason) -> bool {
|
||||
if phase != PHASE_MASK::BUBBLING {
|
||||
return false;
|
||||
}
|
||||
|
||||
if code == BEHAVIOR_EVENTS::BUTTON_CLICK {
|
||||
|
||||
// `root` points to attached element, usually it is an `<html>`.
|
||||
|
||||
let root = Element::from(root).root();
|
||||
|
||||
let message = root.find_first("#message").unwrap().expect("div#message not found");
|
||||
let source = Element::from(source);
|
||||
|
||||
println!("our root is {:?}, message is {:?} and source is {:?}", root, message, source);
|
||||
|
||||
if let Some(id) = source.get_attribute("id") {
|
||||
if id == "send" {
|
||||
|
||||
// just send a simple event
|
||||
source.send_event(BEHAVIOR_EVENTS::CHANGE, None, Some(message.as_ptr())).expect("Failed to send event");
|
||||
return true;
|
||||
|
||||
} else if id == "fire" {
|
||||
|
||||
// fire event with specified params
|
||||
let data = Value::from("Rusty param");
|
||||
|
||||
source.fire_event(BEHAVIOR_EVENTS::CHANGE, None, Some(message.as_ptr()), false, Some(data)).expect("Failed to fire event");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let html = include_bytes!("fire_event.htm");
|
||||
let mut frame = sciter::Window::new();
|
||||
frame.event_handler(FireEvent);
|
||||
frame.load_html(html, Some("example://fire_event.htm"));
|
||||
frame.run_app();
|
||||
}
|
||||
35
libs/rust-sciter/examples/first.rs
Normal file
35
libs/rust-sciter/examples/first.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
//! An example showing various information about Sciter.
|
||||
|
||||
extern crate sciter;
|
||||
|
||||
fn main() {
|
||||
// can be called as `examples/first ~/lib/libsciter.so`
|
||||
if cfg!(feature = "dynamic") {
|
||||
if let Some(arg) = std::env::args().nth(1) {
|
||||
println!("using {:?}", arg);
|
||||
if let Err(e) = sciter::set_library(&arg) {
|
||||
panic!("Invalid library path specified: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let arch = if cfg!(target_arch = "x86_64") { "x64" } else { "x86" };
|
||||
println!("calling SciterAPI {}", arch);
|
||||
|
||||
// bypass the ABI compatability checks (e.g. in windowless builds)
|
||||
let scapi = sciter::SciterAPI_unchecked();
|
||||
|
||||
let abi_version = scapi.version;
|
||||
println!("sciter abi version: {:#0x}, windowless: {}", abi_version, abi_version >= 0x0001_0001);
|
||||
|
||||
let class_name = sciter::utf::w2s((scapi.SciterClassName)());
|
||||
println!("sciter class name: {:?}", class_name);
|
||||
|
||||
// Sciter library version
|
||||
use sciter::types::BOOL;
|
||||
let v1 = (scapi.SciterVersion)(true as BOOL);
|
||||
let v2 = (scapi.SciterVersion)(false as BOOL);
|
||||
let num = [v1 >> 16, v1 & 0xFFFF, v2 >> 16, v2 & 0xFFFF];
|
||||
let version = num.iter().map(|&x| x.to_string()).collect::<Vec<_>>().join(".");
|
||||
println!("sciter version: {} {:?}", version, num);
|
||||
}
|
||||
BIN
libs/rust-sciter/examples/icon.png
Normal file
BIN
libs/rust-sciter/examples/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
90
libs/rust-sciter/examples/interop.htm
Normal file
90
libs/rust-sciter/examples/interop.htm
Normal file
@@ -0,0 +1,90 @@
|
||||
<html window-icon="https://sciter.com/wp-content/themes/sciter/!images/favicon.ico">
|
||||
<head>
|
||||
<title>Rust-sciter sample</title>
|
||||
<style>
|
||||
|
||||
html {
|
||||
background: radial-gradient(75% 75%, circle farthest-side, white, orange, rgb(0,0,204));
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
html:rtl {
|
||||
mapping: left-to-right(background);
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
|
||||
view.caption = $(head > title).value;
|
||||
|
||||
$(#machine).text = Sciter.machineName();
|
||||
$(#backend).text = view.backendName;
|
||||
$(#version).text = String.printf("%d.%d.%d.%d",
|
||||
(Sciter.VERSION >> 16) & 0xffff, Sciter.VERSION & 0xffff,
|
||||
(Sciter.REVISION >> 16) & 0xffff, Sciter.REVISION & 0xffff);
|
||||
|
||||
var counter = 0;
|
||||
$(button#append).on("click", function() {
|
||||
$(body).$append(<h1#test>{ ++counter }</h1>);
|
||||
});
|
||||
|
||||
$(button#open).on("click", function() {
|
||||
|
||||
var fn = view.selectFile(#open,
|
||||
"HTML Files (*.htm,*.html)|*.HTM;*.HTML|All Files (*.*)|*.*" , "html" );
|
||||
|
||||
stdout.println("selected file: " + fn);
|
||||
|
||||
if (fn) {
|
||||
$(body).$append(<h1#test>{fn}</h1>);
|
||||
}
|
||||
});
|
||||
|
||||
$(button#ti2py).on("click", function() {
|
||||
var answer = view.NativeCall(view.caption);
|
||||
$(body).$append(<h1#test>script -> native: {answer}</h1>);
|
||||
})
|
||||
|
||||
$(button#py2ti).on("click", function() {
|
||||
var answer = view.ScriptCallTest("call arg");
|
||||
})
|
||||
|
||||
$(button#sum).on("click", function() {
|
||||
stdout.printf("2 + 3 = %d\n", view.calc_sum(2, 3));
|
||||
})
|
||||
|
||||
function hello(who) {
|
||||
$(body).$append(<h1#test>native -> script: {who}</h1>);
|
||||
return "its working!";
|
||||
}
|
||||
|
||||
function raise_error(arg1, arg2, arg3) {
|
||||
throw new Error(String.$(Unexpected type of input: {typeof arg1}, {typeof arg2}, {typeof arg3}.));
|
||||
}
|
||||
|
||||
self.timer(2000, function() {
|
||||
|
||||
if(!view.api)
|
||||
view.api = view.GetNativeApi();
|
||||
// {add: function(a,b) { return a + b; }};
|
||||
|
||||
stdout.printf("2 + 3 = %d\n", view.api.add(2, 3));
|
||||
stdout.printf("2 * 3 = %d\n", view.api.mul(2, 3));
|
||||
stdout.printf("2 - 3 = %d\n", view.api.sub(2, 3));
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Rust Sciter Application</h1>
|
||||
<p>Running on <strong #machine /> machine via <strong #backend/> (<strong #version/>).</p>
|
||||
|
||||
<button #append>Append</button>
|
||||
<button #open>Open</button>
|
||||
<button #ti2py>Call native</button>
|
||||
<button #py2ti>Call script</button>
|
||||
<button #sum>Calc sum</button>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
180
libs/rust-sciter/examples/interop.rs
Normal file
180
libs/rust-sciter/examples/interop.rs
Normal file
@@ -0,0 +1,180 @@
|
||||
//! Sciter interop with native code and vice versa.
|
||||
|
||||
#![allow(unused_variables)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate sciter;
|
||||
|
||||
use sciter::{HELEMENT, Element, Value};
|
||||
|
||||
struct EventHandler {
|
||||
root: Option<Element>,
|
||||
}
|
||||
|
||||
impl Drop for EventHandler {
|
||||
fn drop(&mut self) {
|
||||
println!("interop::EventHandler: Bye bye, HTML!");
|
||||
}
|
||||
}
|
||||
|
||||
impl EventHandler {
|
||||
|
||||
fn script_call_test(&self, args: &[Value], root: &Element) -> Option<Value> {
|
||||
|
||||
println!("root: {:?}", root);
|
||||
// return None;
|
||||
|
||||
println!("calling 'hello'");
|
||||
let answer = root.call_function("hello", &make_args!("hello, rust!"));
|
||||
println!(" answer {:?}", answer);
|
||||
|
||||
println!("get and call 'hello'");
|
||||
let answer = root.eval_script(r"hello");
|
||||
if answer.is_err() {
|
||||
return None;
|
||||
}
|
||||
let obj = answer.unwrap();
|
||||
let answer = obj.call(None, &make_args!("argument"), None);
|
||||
println!(" answer is {:?}", answer);
|
||||
|
||||
println!("eval 'hello'");
|
||||
let answer = root.eval_script(r#"hello("42");"#);
|
||||
println!(" answer is {:?}", answer);
|
||||
|
||||
println!("calling 'raise_error'; the following exceptions are expected then:");
|
||||
let answer = root.call_function("raise_error", &make_args!(17, "42", false));
|
||||
println!(" answer is {:?}", answer);
|
||||
|
||||
println!("calling inexisting function");
|
||||
let answer = root.call_function("raise_error2", &[]);
|
||||
println!(" answer is {:?}", answer);
|
||||
|
||||
Some(Value::from(true))
|
||||
}
|
||||
|
||||
fn NativeCall(&mut self, arg: String) -> Value {
|
||||
Value::from(format!("Rust window ({})", arg))
|
||||
}
|
||||
|
||||
fn GetNativeApi(&mut self) -> Value {
|
||||
|
||||
fn on_add(args: &[Value]) -> Value {
|
||||
let ints = args.iter().map(|x| x.to_int().unwrap());
|
||||
// let sum: i32 = ints.sum(); // error: issue #27739
|
||||
let sum: i32 = ints.sum();
|
||||
Value::from(sum)
|
||||
}
|
||||
|
||||
fn on_sub(args: &[Value]) -> Value {
|
||||
if args.len() != 2 || args.iter().any(|x| !x.is_int()) {
|
||||
return Value::error("sub requires 2 integer arguments!");
|
||||
}
|
||||
let ints: Vec<_> = args.iter().map(|x| x.to_int().unwrap()).collect();
|
||||
let (a,b) = (ints[0], ints[1]);
|
||||
Value::from(a - b)
|
||||
}
|
||||
|
||||
let on_mul = |args: &[Value]| -> Value {
|
||||
let prod: i32 = args.iter().map(|x| x.to_int().unwrap()).product();
|
||||
Value::from(prod)
|
||||
};
|
||||
|
||||
let mut api = Value::new();
|
||||
|
||||
api.set_item("add", on_add);
|
||||
api.set_item("sub", on_sub);
|
||||
api.set_item("mul", on_mul);
|
||||
|
||||
println!("returning {:?}", api);
|
||||
|
||||
api
|
||||
}
|
||||
|
||||
fn calc_sum(&mut self, a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
impl sciter::EventHandler for EventHandler {
|
||||
|
||||
fn attached(&mut self, root: HELEMENT) {
|
||||
self.root = Some(Element::from(root));
|
||||
}
|
||||
|
||||
dispatch_script_call! {
|
||||
|
||||
fn NativeCall(String);
|
||||
|
||||
fn GetNativeApi();
|
||||
|
||||
fn calc_sum(i32, i32);
|
||||
}
|
||||
|
||||
fn on_script_call(&mut self, root: HELEMENT, name: &str, argv: &[Value]) -> Option<Value> {
|
||||
|
||||
let args = argv.iter().map(|x| format!("{:?}", &x)).collect::<Vec<String>>().join(", ");
|
||||
println!("script->native: {}({}), root {:?}", name, args, Element::from(root));
|
||||
|
||||
let handled = self.dispatch_script_call(root, name, argv);
|
||||
if handled.is_some() {
|
||||
return handled;
|
||||
}
|
||||
|
||||
if name == "ScriptCallTest" {
|
||||
return self.script_call_test(argv, &Element::from(root));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn check_options() {
|
||||
sciter::set_options(sciter::RuntimeOptions::ScriptFeatures(
|
||||
sciter::SCRIPT_RUNTIME_FEATURES::ALLOW_SYSINFO as u8 // Enables `Sciter.machineName()`
|
||||
| sciter::SCRIPT_RUNTIME_FEATURES::ALLOW_FILE_IO as u8 // Enables opening file dialog (`view.selectFile()`)
|
||||
)).ok();
|
||||
|
||||
for arg in std::env::args() {
|
||||
if arg.starts_with("--sciter-gfx=") {
|
||||
use sciter::GFX_LAYER;
|
||||
let backend = match arg.split_at("--sciter-gfx=".len()).1.trim() {
|
||||
"auto" => GFX_LAYER::AUTO,
|
||||
"cpu" => GFX_LAYER::CPU,
|
||||
"skia" | "skia-cpu" => GFX_LAYER::SKIA_CPU,
|
||||
"skia-opengl" => GFX_LAYER::SKIA_OPENGL,
|
||||
|
||||
#[cfg(windows)]
|
||||
"d2d" => GFX_LAYER::D2D,
|
||||
#[cfg(windows)]
|
||||
"warp" => GFX_LAYER::WARP,
|
||||
|
||||
_ => GFX_LAYER::AUTO,
|
||||
};
|
||||
println!("setting {:?} backend", backend);
|
||||
let ok = sciter::set_options(sciter::RuntimeOptions::GfxLayer(backend));
|
||||
if let Err(e) = ok {
|
||||
println!("failed to set backend: {:?}", e);
|
||||
}
|
||||
|
||||
} else if arg.starts_with("--ux-theme") {
|
||||
#[cfg(windows)]
|
||||
sciter::set_options(sciter::RuntimeOptions::UxTheming(true)).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// interop --sciter-gfx=cpu --ux-theme
|
||||
check_options();
|
||||
|
||||
let html = include_bytes!("interop.htm");
|
||||
let handler = EventHandler { root: None };
|
||||
let mut frame = sciter::Window::new();
|
||||
frame.event_handler(handler);
|
||||
frame.load_html(html, Some("example://interop.htm"));
|
||||
frame.run_app();
|
||||
}
|
||||
88
libs/rust-sciter/examples/minimal.htm
Normal file
88
libs/rust-sciter/examples/minimal.htm
Normal file
@@ -0,0 +1,88 @@
|
||||
<html window-icon="https://sciter.com/wp-content/themes/sciter/!images/favicon.ico">
|
||||
<head>
|
||||
<title>Minimalistic Sciter demo</title>
|
||||
<style>
|
||||
|
||||
html {
|
||||
background: radial-gradient(75% 75%, circle farthest-side, white, orange, rgb(0,0,204));
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
html:rtl {
|
||||
mapping: left-to-right(background);
|
||||
}
|
||||
|
||||
a { color: white; }
|
||||
code { font-weight: bold; }
|
||||
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
view.caption = $(head > title).value;
|
||||
|
||||
$(#machine).text = Sciter.machineName();
|
||||
$(#version).text = String.printf("%d.%d.%d.%d",
|
||||
(Sciter.VERSION >> 16) & 0xffff, Sciter.VERSION & 0xffff,
|
||||
(Sciter.REVISION >> 16) & 0xffff, Sciter.REVISION & 0xffff);
|
||||
|
||||
try {
|
||||
// since 4.2.5.0
|
||||
$(#revision).text = Sciter.BUILD.toString();
|
||||
} catch(e) {
|
||||
$(#revision).text = "N/A";
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
|
||||
$(button#append).on("click", function() {
|
||||
$(body).$append(<h1#test>{ ++counter }</h1>);
|
||||
});
|
||||
|
||||
$(button#open).on("click", function() {
|
||||
|
||||
var fn = view.selectFile(#open,
|
||||
"HTML Files (*.htm,*.html)|*.HTM;*.HTML|All Files (*.*)|*.*" , "html" );
|
||||
|
||||
// if the dialog was closed or
|
||||
// filesystem interaction was disabled via `ALLOW_FILE_IO`
|
||||
// the selected file `fn` would be `undefined`.
|
||||
stdout.println("selected file: " + fn);
|
||||
|
||||
if (fn) {
|
||||
$(body).$append(<h1#test>{fn}</h1>);
|
||||
}
|
||||
});
|
||||
|
||||
// Some tricks with hyperlinks:
|
||||
$(a).on("click", function() {
|
||||
Sciter.launch(this.attributes["href"]);
|
||||
return true;
|
||||
});
|
||||
|
||||
for (var a in $$(a)) {
|
||||
a.attributes["title"] = a.attributes["href"];
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Minimal Sciter Application</h1>
|
||||
<p>Running on <em #machine /> machine</p>
|
||||
<p>Sciter version <span #version /> rev <span #revision /></p>
|
||||
|
||||
<button #append>Append</button>
|
||||
<button #open>Open</button>
|
||||
<select>
|
||||
<option>Some</option>
|
||||
<option>Items</option>
|
||||
<option>in select</option>
|
||||
</select>
|
||||
|
||||
<section class=footer>
|
||||
<p>You can inspect this window in the <a href="https://sciter.com/developers/development-tools/">Inspector tool</a>
|
||||
from the <a href="https://sciter.com/download/">Sciter SDK</a>.</p>
|
||||
<p>Run the Inspector first and then press <code>CTRL+SHIFT+I</code> in this window.</p>
|
||||
</section>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
43
libs/rust-sciter/examples/minimal.rs
Normal file
43
libs/rust-sciter/examples/minimal.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
//! Minimalistic Sciter sample.
|
||||
|
||||
// Specify the Windows subsystem to eliminate console window.
|
||||
// Requires Rust 1.18.
|
||||
#![windows_subsystem="windows"]
|
||||
|
||||
extern crate sciter;
|
||||
|
||||
fn main() {
|
||||
// Step 1: Include the 'minimal.html' file as a byte array.
|
||||
// Hint: Take a look into 'minimal.html' which contains some tiscript code.
|
||||
let html = include_bytes!("minimal.htm");
|
||||
|
||||
// Step 2: Enable the features we need in our tiscript code.
|
||||
sciter::set_options(sciter::RuntimeOptions::ScriptFeatures(
|
||||
sciter::SCRIPT_RUNTIME_FEATURES::ALLOW_SYSINFO as u8 // Enables `Sciter.machineName()`
|
||||
| sciter::SCRIPT_RUNTIME_FEATURES::ALLOW_FILE_IO as u8 // Enables opening file dialog (`view.selectFile()`)
|
||||
)).unwrap();
|
||||
|
||||
// Enable debug mode for all windows, so that we can inspect them via Inspector.
|
||||
sciter::set_options(sciter::RuntimeOptions::DebugMode(true)).unwrap();
|
||||
|
||||
// Step 3: Create a new main sciter window of type `sciter::Window`.
|
||||
// Hint: The sciter Window wrapper (src/window.rs) contains more
|
||||
// interesting functions to open or attach to another existing window.
|
||||
let mut frame = sciter::Window::new();
|
||||
|
||||
if cfg!(target_os="macos") {
|
||||
// a temporary workaround for OSX, see
|
||||
// https://sciter.com/forums/topic/global-sciter_set_debug_mode-does-not-work-in-osx/
|
||||
frame.set_options(sciter::window::Options::DebugMode(true)).unwrap();
|
||||
}
|
||||
|
||||
// Step 4: Load HTML byte array from memory to `sciter::Window`.
|
||||
// Hint: second parameter is an optional uri, it can be `None` in simple cases,
|
||||
// but it is useful for debugging purposes (check the Inspector tool from the Sciter SDK).
|
||||
// Also you can use a `load_file` method, but it requires an absolute path
|
||||
// of the main document to resolve HTML resources properly.
|
||||
frame.load_html(html, Some("example://minimal.htm"));
|
||||
|
||||
// Step 5: Show window and run the main app message loop until window been closed.
|
||||
frame.run_app();
|
||||
}
|
||||
67
libs/rust-sciter/examples/som.htm
Normal file
67
libs/rust-sciter/examples/som.htm
Normal file
@@ -0,0 +1,67 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>SOM test</title>
|
||||
<style type="text/css">
|
||||
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
if(0) {
|
||||
debug(asset traits);
|
||||
debug: Asset.typeOf(TestGlobal);
|
||||
debug: Asset.hasProperty(TestGlobal, #age);
|
||||
debug: Asset.hasMethod(TestGlobal, #print);
|
||||
|
||||
debug(asset globals);
|
||||
debug: TestGlobal;
|
||||
debug: view.TestGlobal;
|
||||
debug: view.root.TestGlobal;
|
||||
|
||||
debug(asset properties);
|
||||
debug: TestGlobal.age;
|
||||
|
||||
TestGlobal.age = 17;
|
||||
debug: TestGlobal.age;
|
||||
|
||||
TestGlobal.name = "Demogor";
|
||||
debug: TestGlobal.name;
|
||||
|
||||
debug: TestGlobal.print();
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
if(1) {
|
||||
debug(event handler);
|
||||
|
||||
debug(implicit access);
|
||||
var prop = view.TestGlobal;
|
||||
debug: prop;
|
||||
|
||||
var int_prop = prop.age;
|
||||
debug: int_prop;
|
||||
|
||||
debug(explicit access);
|
||||
debug: view.TestGlobal;
|
||||
|
||||
var val = view.TestGlobal.age;
|
||||
debug: val;
|
||||
|
||||
debug: view.TestGlobal.age;
|
||||
|
||||
view.TestGlobal.age = 12;
|
||||
debug: view.TestGlobal.age;
|
||||
|
||||
debug: view.TestGlobal.print();
|
||||
|
||||
debug: view.TestGlobal.add_year(12);
|
||||
debug: view.TestGlobal.age;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div>Hello, body</div>
|
||||
<p>but open Inspector to see the logs</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
193
libs/rust-sciter/examples/som.rs
Normal file
193
libs/rust-sciter/examples/som.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
// there are logs in console window
|
||||
// #![windows_subsystem="windows"]
|
||||
extern crate sciter;
|
||||
|
||||
use sciter::{HELEMENT, types::{BOOL, VALUE}};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Object {
|
||||
age: i32,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl Object {
|
||||
pub fn print(&self) -> String {
|
||||
format!("name: {}, age: {}", self.name, self.age)
|
||||
}
|
||||
|
||||
pub fn add_year(&mut self, v: i32) -> i32 {
|
||||
self.age += v;
|
||||
self.age
|
||||
}
|
||||
}
|
||||
|
||||
// SOM Passport of the asset.
|
||||
// TODO: should be auto-generated.
|
||||
impl sciter::om::Passport for Object {
|
||||
fn get_passport(&self) -> &'static sciter::om::som_passport_t {
|
||||
use sciter::om::*;
|
||||
|
||||
extern "C" fn on_print(thing: *mut som_asset_t, _argc: u32, _argv: *const VALUE, p_result: &mut VALUE) -> BOOL
|
||||
{
|
||||
let me = IAsset::<Object>::from_raw(&thing);
|
||||
let r = me.print();
|
||||
let r: sciter::Value = r.into();
|
||||
r.pack_to(p_result);
|
||||
return true as BOOL;
|
||||
}
|
||||
extern "C" fn on_add_year(thing: *mut som_asset_t, argc: u32, argv: *const VALUE, p_result: &mut VALUE) -> BOOL
|
||||
{
|
||||
let me = IAsset::<Object>::from_raw(&thing);
|
||||
|
||||
let args = unsafe { sciter::Value::unpack_from(argv, argc) };
|
||||
let required = 1;
|
||||
if args.len() != required {
|
||||
let r = sciter::Value::error(&format!("{} error: {} of {} arguments provided.", "Object::add_year", args.len(), required));
|
||||
r.pack_to(p_result);
|
||||
return true as BOOL;
|
||||
}
|
||||
|
||||
let r = me.add_year(
|
||||
match sciter::FromValue::from_value(&args[0]) {
|
||||
Some(arg) => arg,
|
||||
None => {
|
||||
let r = sciter::Value::error(&format!("{} error: invalid type of {} argument ({} expected, {:?} provided).",
|
||||
"Object::add_year", 0, "i32", &args[0]
|
||||
));
|
||||
r.pack_to(p_result);
|
||||
return true as BOOL;
|
||||
}
|
||||
},
|
||||
);
|
||||
let r: sciter::Value = r.into();
|
||||
r.pack_to(p_result);
|
||||
return true as BOOL;
|
||||
}
|
||||
|
||||
extern "C" fn on_get_age(thing: *mut som_asset_t, p_value: &mut VALUE) -> BOOL
|
||||
{
|
||||
let me = IAsset::<Object>::from_raw(&thing);
|
||||
let r = sciter::Value::from(&me.age);
|
||||
r.pack_to(p_value);
|
||||
return true as BOOL;
|
||||
}
|
||||
extern "C" fn on_set_age(thing: *mut som_asset_t, p_value: &VALUE) -> BOOL
|
||||
{
|
||||
let me = IAsset::<Object>::from_raw(&thing);
|
||||
use sciter::FromValue;
|
||||
let v = sciter::Value::from(p_value);
|
||||
if let Some(v) = FromValue::from_value(&v) {
|
||||
me.age = v;
|
||||
true as BOOL
|
||||
} else {
|
||||
false as BOOL
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn on_get_name(thing: *mut som_asset_t, p_value: &mut VALUE) -> BOOL
|
||||
{
|
||||
let me = IAsset::<Object>::from_raw(&thing);
|
||||
let r = sciter::Value::from(&me.name);
|
||||
r.pack_to(p_value);
|
||||
return true as BOOL;
|
||||
}
|
||||
extern "C" fn on_set_name(thing: *mut som_asset_t, p_value: &VALUE) -> BOOL
|
||||
{
|
||||
let me = IAsset::<Object>::from_raw(&thing);
|
||||
use sciter::FromValue;
|
||||
let v = sciter::Value::from(p_value);
|
||||
if let Some(v) = FromValue::from_value(&v) {
|
||||
me.name = v;
|
||||
true as BOOL
|
||||
} else {
|
||||
false as BOOL
|
||||
}
|
||||
}
|
||||
|
||||
type ObjectMethods = [som_method_def_t; 2];
|
||||
|
||||
let mut methods = Box::new(ObjectMethods::default());
|
||||
|
||||
let mut method = &mut methods[0];
|
||||
method.name = atom("print");
|
||||
method.func = Some(on_print);
|
||||
method.params = 0;
|
||||
|
||||
let mut method = &mut methods[1];
|
||||
method.name = atom("add_year");
|
||||
method.func = Some(on_add_year);
|
||||
method.params = 1;
|
||||
|
||||
type ObjectProps = [som_property_def_t; 2];
|
||||
|
||||
let mut props = Box::new(ObjectProps::default());
|
||||
|
||||
let mut prop = &mut props[0];
|
||||
prop.name = atom("age");
|
||||
prop.getter = Some(on_get_age);
|
||||
prop.setter = Some(on_set_age);
|
||||
|
||||
let mut prop = &mut props[1];
|
||||
prop.name = atom("name");
|
||||
prop.getter = Some(on_get_name);
|
||||
prop.setter = Some(on_set_name);
|
||||
|
||||
let mut pst = Box::new(som_passport_t::default());
|
||||
pst.name = atom("TestGlobal");
|
||||
|
||||
pst.n_methods = 2;
|
||||
pst.methods = Box::into_raw(methods) as *const _;
|
||||
|
||||
pst.n_properties = 2;
|
||||
pst.properties = Box::into_raw(props) as *const _;
|
||||
|
||||
Box::leak(pst)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Handler {
|
||||
asset: sciter::om::IAssetRef<Object>,
|
||||
}
|
||||
|
||||
impl sciter::EventHandler for Handler {
|
||||
fn attached(&mut self, _root: HELEMENT) {
|
||||
println!("attached");
|
||||
}
|
||||
fn detached(&mut self, _root: HELEMENT) {
|
||||
println!("detached");
|
||||
}
|
||||
fn document_complete(&mut self, _root: HELEMENT, _target: HELEMENT) {
|
||||
println!("loaded");
|
||||
}
|
||||
|
||||
fn get_asset(&mut self) -> Option<&sciter::om::som_asset_t> {
|
||||
Some(self.asset.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
sciter::set_options(sciter::RuntimeOptions::DebugMode(true)).unwrap();
|
||||
|
||||
let mut frame = sciter::Window::new();
|
||||
|
||||
let object = Object::default();
|
||||
let object = sciter::om::IAsset::new(object);
|
||||
sciter::om::into_global(object);
|
||||
|
||||
let object2 = Object::default();
|
||||
let object2 = sciter::om::IAsset::new(object2);
|
||||
let object2 = sciter::om::IAssetRef::from(object2);
|
||||
let ptr = object2.as_ptr();
|
||||
let psp = object2.get_passport();
|
||||
println!{"asset {:?} psp {:?}", ptr, psp as *const _};
|
||||
println!("asset: {:?}", object2);
|
||||
|
||||
let handler = Handler { asset: object2 };
|
||||
frame.event_handler(handler);
|
||||
|
||||
let html = include_bytes!("som.htm");
|
||||
frame.load_html(html, Some("example://som.htm"));
|
||||
frame.run_app();
|
||||
}
|
||||
82
libs/rust-sciter/examples/threads.htm
Normal file
82
libs/rust-sciter/examples/threads.htm
Normal file
@@ -0,0 +1,82 @@
|
||||
<html window-icon="https://cdn2.iconfinder.com/data/icons/arts-crafts-sewing/24/sewing_thread_handcraft_craft_1-32.png">
|
||||
<head>
|
||||
<title>Threads demo</title>
|
||||
<style>
|
||||
div#content { flow:horizontal; size:*; }
|
||||
div#explanation { size:*; padding:20px; overflow:auto; }
|
||||
div#explanation > pre { padding:10px; border:1px dotted #999; background:#ffffef; }
|
||||
|
||||
div#tasks { width:300px; height:*; }
|
||||
div#tasks > select { size:*; display:block; }
|
||||
div#tasks > select progress { margin-left: 5px; }
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
|
||||
var taskNo = 0;
|
||||
|
||||
$(#start-task).onClick = function()
|
||||
{
|
||||
++taskNo;
|
||||
|
||||
var taskElem = $(div#tasks > select).$append(<option>Task { taskNo }<progress max=100 /> <span.result /></option>);
|
||||
|
||||
function onProgress(p100) { taskElem.$(progress).value = p100; }
|
||||
function onDone(taskId) {
|
||||
taskElem.$(span.result).text = "Done!";
|
||||
taskElem.$(progress).remove();
|
||||
}
|
||||
|
||||
view.exec_task(taskNo, onProgress, onDone);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Sciter UI, threads demo</h2>
|
||||
<div id="content">
|
||||
<div id="tasks">
|
||||
<button id="start-task">Start Task</button>
|
||||
<select type="select"></select>
|
||||
</div>
|
||||
<div id="explanation">
|
||||
<p>The Start Task onClick handler is defined as</p>
|
||||
<pre>
|
||||
$(#start-task).onClick = function()
|
||||
{
|
||||
var taskElem = $(div#tasks > select)
|
||||
.$append(<option>Task { ++taskNo }
|
||||
<progress max=100 />
|
||||
<span.result /></option>);
|
||||
function onProgress(p100) {
|
||||
taskElem.$(progress).value = p100;
|
||||
}
|
||||
function onDone(taskId) {
|
||||
taskElem.$(span.result).text = "Done!";
|
||||
taskElem.$(progress).remove();
|
||||
}
|
||||
view.exec_task(taskId, onProgress, onDone);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>It defines couple of callback functions and calls <code>view.exec_task()</code> with them.</p>
|
||||
<p>The <code>view.exec_task()</code> native method is implemented in <code>EventHandler::exec_task()</code>.</p>
|
||||
<p>The <code>EventHandler::exec_task()</code> starts worker thread passing <em>taskNo</em>, <em>onProgress</em> and
|
||||
<em>onDone</em> parameters to it.</p>
|
||||
<p>Worker thread body is defined in Rust code as:</p>
|
||||
<pre>
|
||||
// worker thread body, simulate time consuming task
|
||||
fn thread_body(task_no: i32, progress: Value, done: Value)
|
||||
{
|
||||
for i in 1..100 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
progress.call(None, &make_args!(i), None).unwrap(); // report task progress
|
||||
}
|
||||
// report task completion,
|
||||
// we can pass some result data here, for now just taskId
|
||||
done.call(None, &make_args!(task_no), None).unwrap();
|
||||
}
|
||||
</pre>
|
||||
<p>As you see it calls passed callback functions.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
42
libs/rust-sciter/examples/threads.rs
Normal file
42
libs/rust-sciter/examples/threads.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
#[macro_use]
|
||||
extern crate sciter;
|
||||
use sciter::Value;
|
||||
|
||||
struct EventHandler;
|
||||
|
||||
impl EventHandler {
|
||||
// script handler
|
||||
fn exec_task(&self, task_no: i32, progress: sciter::Value, done: sciter::Value) -> bool {
|
||||
|
||||
use std::{thread, time};
|
||||
thread::spawn(move || {
|
||||
|
||||
for i in 1..100 {
|
||||
// call `onProgress` callback
|
||||
thread::sleep(time::Duration::from_millis(100));
|
||||
progress.call(None, &make_args!(i), None).unwrap();
|
||||
}
|
||||
|
||||
// call `onDone` callback
|
||||
done.call(None, &make_args!(task_no), None).unwrap();
|
||||
});
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl sciter::EventHandler for EventHandler {
|
||||
// route script calls to our handler
|
||||
dispatch_script_call! {
|
||||
fn exec_task(i32, Value, Value);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let html = include_bytes!("threads.htm");
|
||||
let mut frame = sciter::WindowBuilder::main_window()
|
||||
.with_size((1200, 900))
|
||||
.create();
|
||||
frame.event_handler(EventHandler);
|
||||
frame.load_html(html, None);
|
||||
frame.run_app();
|
||||
}
|
||||
122
libs/rust-sciter/examples/video.htm
Normal file
122
libs/rust-sciter/examples/video.htm
Normal file
@@ -0,0 +1,122 @@
|
||||
<html window-icon="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB1UlEQVR4nJWTP2hTcRDHP3epS4TqqHHtVNNCFzNFaZD8sxQkKQrOUnCLBoIoOIkG0nYQBbO4OiRLadpEIQ6dxEGxcdclg6Ngpt/vPZd78vqwBQ+O3933vtz97o4TEvKodDkP3ADyQNbgCXAIDJ6Ovh3G+RIZD0vZDNAENoF0MrHJDHgNdJ6NJlMABWiVljIBshUgjQBJB8iHANkMEAKkZu/QYo0A2WqVljJ/E3i06dHbHv3u0QceXWuPjroexaP99uhIPFqz2NS4TQBplFfywPCUb0fS2xl+3miUV+4CXWunnLqycOleiKyGSC1EboUIJ+hibiEzDZFiiCyGyJkQ+Tnn0LxV6Ccq/gBemv0YmAeKQB2oGT+vDs06FIcuvxp+ErNx6HmHVhxadui8YRcc2nNo3/ysOklhKgAx/5yT1KqTVCGGvegOP244SS1HmHp0YtO+ZhuJ9ItHczbxCHtinK/mT+RO5epzoAX8sj6TkgPenxBrq0MHDp3F+kyqOvTNP/CZQwcCUK8UtoFGbLpnewfjWbxUvVJIA79jnJ3ewfj+HIAX7QAXY6vcu1m9vguMzS94WI+t+y3QgdgxrVeL/3VMu/vvpscSRLJWLZ16znv7o2Pn/AeeJco8j/W3vQAAAABJRU5ErkJggg==">
|
||||
<head>
|
||||
<title>Video behavior demo</title>
|
||||
<style>
|
||||
body { background: gold; padding: 5dip; margin: 0; }
|
||||
|
||||
form { margin: 5dip; }
|
||||
|
||||
p { padding: 4dip; }
|
||||
|
||||
video.generator {
|
||||
behavior: video-generator video;
|
||||
border: 1px solid orange;
|
||||
size: *;
|
||||
foreground-size: contain;
|
||||
}
|
||||
|
||||
</style>
|
||||
<script type="text/tiscript">
|
||||
|
||||
$(video).onSize = function() {
|
||||
var (w,h) = this.box(#dimension);
|
||||
$(form).value = { width: w, height: h };
|
||||
}
|
||||
|
||||
function self.ready() {
|
||||
var (w,h) = this.box(#dimension);
|
||||
$(form).value = { width: w, height: h };
|
||||
}
|
||||
|
||||
event click $(#snapshot) {
|
||||
var curframe = $(video).style.foregroundImage;
|
||||
var fname = view.selectFile(#save, "Images|*.png;*.jpg|All files|*.*", "png");
|
||||
if (fname) {
|
||||
var image = curframe.toBytes();
|
||||
image.save(fname);
|
||||
}
|
||||
}
|
||||
|
||||
var video = $(video);
|
||||
var host;
|
||||
var body = $(body);
|
||||
|
||||
event click $(#show-detached) {
|
||||
|
||||
if (body && !video.parent) {
|
||||
// recreate element
|
||||
video = body.$append(<video class="generator" />);
|
||||
}
|
||||
|
||||
// It creates a new window and moves the current video element to it.
|
||||
if( this.value )
|
||||
{
|
||||
host = view.window {
|
||||
type: View.TOOL_WINDOW,
|
||||
html: $(#templates).text,
|
||||
width: 640,
|
||||
height: 480,
|
||||
alignment: 5,
|
||||
};
|
||||
video.detach();
|
||||
host.root.$(body).append(video);
|
||||
|
||||
host.on("closing", function(evt) {
|
||||
// detach
|
||||
video.detach();
|
||||
body.append(video);
|
||||
$(#show-detached).value = false;
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
// and back
|
||||
video.detach();
|
||||
body.append(video);
|
||||
host.close();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script id="templates" type="text/html+template">
|
||||
|
||||
<html window-resizable>
|
||||
<head>
|
||||
<title>Hosted element</title>
|
||||
<style>
|
||||
body { margin: 0; padding: 0; }
|
||||
|
||||
video.generator {
|
||||
display: block;
|
||||
behavior: video-generator video;
|
||||
size: *;
|
||||
foreground-size: contain;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>This demo simulates partial video frame update.
|
||||
On each frame (24 FPS) it updates another portion of the frame.</p>
|
||||
|
||||
<div>
|
||||
<button id="snapshot">Save the current frame</button>
|
||||
<button type=checkbox id="show-detached">Show video in a separate window</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<form>frame size: <output name=width /> x <output name=height /></form>
|
||||
</div>
|
||||
|
||||
<video class="generator" />
|
||||
|
||||
</body>
|
||||
</html>
|
||||
177
libs/rust-sciter/examples/video.rs
Normal file
177
libs/rust-sciter/examples/video.rs
Normal file
@@ -0,0 +1,177 @@
|
||||
#![allow(unused_variables, unused_must_use)]
|
||||
|
||||
extern crate sciter;
|
||||
|
||||
use sciter::dom::event::*;
|
||||
use sciter::{Element, HELEMENT};
|
||||
|
||||
use sciter::video::{fragmented_video_destination, AssetPtr};
|
||||
|
||||
struct VideoGen {
|
||||
thread: Option<std::thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Drop for VideoGen {
|
||||
fn drop(&mut self) {
|
||||
println!("[video] behavior is destroyed");
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoGen {
|
||||
fn new() -> Self {
|
||||
Self { thread: None }
|
||||
}
|
||||
|
||||
fn generation_thread(site: AssetPtr<fragmented_video_destination>) {
|
||||
println!("[video] thread is started");
|
||||
|
||||
// our video frame size and its part to update
|
||||
const FRAME: (i32, i32) = (1200, 800);
|
||||
const UPDATE: (i32, i32) = (256, 32);
|
||||
|
||||
// our frame data (RGBA)
|
||||
let figure = [0xFF_FFA500u32; (UPDATE.0 * UPDATE.1) as usize];
|
||||
|
||||
// configure video output
|
||||
let mut site = site;
|
||||
let ok = site.start_streaming(FRAME, sciter::video::COLOR_SPACE::Rgb32, None);
|
||||
println!("[video] initialized: {:?}", ok);
|
||||
|
||||
let mut x = 0;
|
||||
let mut xd = 1;
|
||||
let mut y = 0;
|
||||
let mut yd = 1;
|
||||
while site.is_alive() {
|
||||
// send an update portion
|
||||
let buf: &[u8] = unsafe { std::mem::transmute(figure.as_ref()) };
|
||||
site.render_frame_part(buf, (x, y), UPDATE);
|
||||
|
||||
// set the next position
|
||||
x += xd;
|
||||
y += yd;
|
||||
|
||||
if x == 0 {
|
||||
xd = 1;
|
||||
} else if x + UPDATE.0 == FRAME.0 {
|
||||
xd = -1;
|
||||
}
|
||||
if y == 0 {
|
||||
yd = 1;
|
||||
} else if y + UPDATE.1 == FRAME.1 {
|
||||
yd = -1;
|
||||
}
|
||||
|
||||
// simulate 25 FPS
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000 / 25));
|
||||
}
|
||||
|
||||
site.stop_streaming();
|
||||
println!("[video] thread is finished");
|
||||
}
|
||||
}
|
||||
|
||||
impl sciter::EventHandler for VideoGen {
|
||||
fn get_subscription(&mut self) -> Option<EVENT_GROUPS> {
|
||||
Some(EVENT_GROUPS::HANDLE_BEHAVIOR_EVENT)
|
||||
}
|
||||
|
||||
fn detached(&mut self, _root: HELEMENT) {
|
||||
println!("[video] <video> element is detached");
|
||||
if let Some(h) = self.thread.take() {
|
||||
h.join();
|
||||
}
|
||||
}
|
||||
|
||||
fn on_event(
|
||||
&mut self,
|
||||
root: HELEMENT,
|
||||
source: HELEMENT,
|
||||
target: HELEMENT,
|
||||
code: BEHAVIOR_EVENTS,
|
||||
phase: PHASE_MASK,
|
||||
reason: EventReason,
|
||||
) -> bool {
|
||||
if phase != PHASE_MASK::BUBBLING {
|
||||
return false;
|
||||
}
|
||||
|
||||
match code {
|
||||
BEHAVIOR_EVENTS::VIDEO_BIND_RQ => {
|
||||
let source = Element::from(source);
|
||||
println!("[video] {:?} {} ({:?})", code, source, reason);
|
||||
|
||||
if let EventReason::VideoBind(ptr) = reason {
|
||||
if ptr.is_null() {
|
||||
// first, consume the event to announce us as a video producer.
|
||||
return true;
|
||||
}
|
||||
|
||||
use sciter::video::*;
|
||||
|
||||
// `VideoBind` comes with a video_destination interface
|
||||
let mut site = AssetPtr::from(ptr as *mut video_destination);
|
||||
|
||||
// query a fragmented video destination interface
|
||||
if let Ok(fragmented) = AssetPtr::<fragmented_video_destination>::try_from(&mut site) {
|
||||
// and use it
|
||||
println!("[video] start video thread");
|
||||
|
||||
let tid = ::std::thread::spawn(|| VideoGen::generation_thread(fragmented));
|
||||
self.thread = Some(tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BEHAVIOR_EVENTS::VIDEO_INITIALIZED => {
|
||||
println!("[video] {:?}", code);
|
||||
}
|
||||
|
||||
BEHAVIOR_EVENTS::VIDEO_STARTED => {
|
||||
println!("[video] {:?}", code);
|
||||
|
||||
let source = Element::from(source);
|
||||
use sciter::dom::ELEMENT_AREAS;
|
||||
let flags = ELEMENT_AREAS::CONTENT_BOX as u32 | ELEMENT_AREAS::SELF_RELATIVE as u32;
|
||||
let rc = source.get_location(flags).unwrap();
|
||||
println!("[video] start video thread on <{}> which is about {:?} pixels", source, rc.size());
|
||||
}
|
||||
|
||||
BEHAVIOR_EVENTS::VIDEO_STOPPED => {
|
||||
println!("[video] {:?}", code);
|
||||
}
|
||||
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if cfg!(all(target_os = "windows", target_arch = "x86")) {
|
||||
println!("\nerror: Sciter video will not work on Windows x86.");
|
||||
println!("error: Consider using a nightly Rust version to enable `abi_thiscall`,");
|
||||
println!("error: see https://github.com/rust-lang/rust/issues/42202");
|
||||
println!("");
|
||||
std::process::exit(126);
|
||||
}
|
||||
|
||||
if sciter::version_num() < 0x04_04_02_0E {
|
||||
// since 4.4.2.14
|
||||
println!("\nerror: `sciter::video` requires SOM support.");
|
||||
println!("error: Sciter API was changed in '4.4.2.14'");
|
||||
println!("error: Sciter version is '{}' now", sciter::version());
|
||||
println!("error: see https://sciter.com/native-code-exposure-to-script/");
|
||||
println!("error: and https://sciter.com/developers/for-native-gui-programmers/sciter-object-model/");
|
||||
println!("");
|
||||
std::process::exit(126);
|
||||
}
|
||||
|
||||
let mut frame = sciter::WindowBuilder::main_window()
|
||||
.with_size((750, 750))
|
||||
.create();
|
||||
frame.set_title("Video renderer sample");
|
||||
frame.register_behavior("video-generator", || Box::new(VideoGen::new()));
|
||||
frame.load_html(include_bytes!("video.htm"), Some("example://video.htm"));
|
||||
frame.run_app();
|
||||
}
|
||||
320
libs/rust-sciter/examples/windowless.rs
Normal file
320
libs/rust-sciter/examples/windowless.rs
Normal file
@@ -0,0 +1,320 @@
|
||||
//! Windowless mode example (for Sciter.Lite build).
|
||||
extern crate sciter;
|
||||
extern crate winit;
|
||||
extern crate winapi;
|
||||
extern crate raw_window_handle;
|
||||
|
||||
|
||||
fn main() {
|
||||
// "Windowless" Sciter builds are incompatible with the regular ones.
|
||||
if !cfg!(feature = "windowless") {
|
||||
panic!("This example requires \"windowless\" feature!");
|
||||
}
|
||||
|
||||
// We need this to explicitly set path to the windowless sciter dll.
|
||||
if !cfg!(feature = "dynamic") {
|
||||
panic!("This example requires the \"dynamic\" feature enabled.")
|
||||
}
|
||||
|
||||
if let Some(arg) = std::env::args().nth(1) {
|
||||
println!("loading sciter from {:?}", arg);
|
||||
if let Err(_) = sciter::set_options(sciter::RuntimeOptions::LibraryPath(&arg)) {
|
||||
panic!("Invalid sciter-lite dll specified.");
|
||||
}
|
||||
}
|
||||
|
||||
// prepare and create a new window
|
||||
println!("create window");
|
||||
let mut events = winit::EventsLoop::new();
|
||||
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
let wnd = winit::WindowBuilder::new();
|
||||
let wnd = wnd.build(&events).expect("Failed to create window");
|
||||
let window_handle = wnd.raw_window_handle();
|
||||
|
||||
// configure Sciter
|
||||
println!("create sciter instance");
|
||||
sciter::set_options(sciter::RuntimeOptions::UxTheming(true)).unwrap();
|
||||
sciter::set_options(sciter::RuntimeOptions::DebugMode(true)).unwrap();
|
||||
sciter::set_options(sciter::RuntimeOptions::ScriptFeatures(0xFF)).unwrap();
|
||||
|
||||
// create an engine instance with an opaque pointer as an identifier
|
||||
use sciter::windowless::{Message, handle_message};
|
||||
let scwnd = { &wnd as *const _ as sciter::types::HWINDOW };
|
||||
handle_message(scwnd, Message::Create { backend: sciter::types::GFX_LAYER::SKIA_OPENGL, transparent: false, });
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// Windows-specific: we need to redraw window in responce to the corresponding notification.
|
||||
// winit 0.20 has an explicit `Window::request_redraw` method,
|
||||
// here we use `winapi::InvalidateRect` for this.
|
||||
struct WindowlessHandler {
|
||||
hwnd: winapi::shared::windef::HWND,
|
||||
}
|
||||
|
||||
impl sciter::HostHandler for WindowlessHandler {
|
||||
fn on_invalidate(&mut self, pnm: &sciter::host::SCN_INVALIDATE_RECT) {
|
||||
unsafe {
|
||||
let rc = &pnm.invalid_rect;
|
||||
let dst = winapi::shared::windef::RECT {
|
||||
left: rc.left,
|
||||
top: rc.top,
|
||||
right: rc.right,
|
||||
bottom: rc.bottom,
|
||||
};
|
||||
winapi::um::winuser::InvalidateRect(self.hwnd, &dst as *const _, 0);
|
||||
// println!("- {} {}", rc.width(), rc.height());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let handler = WindowlessHandler {
|
||||
hwnd: match window_handle {
|
||||
raw_window_handle::RawWindowHandle::Windows(data) => data.hwnd as winapi::shared::windef::HWND,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
};
|
||||
|
||||
let instance = sciter::Host::attach_with(scwnd, handler);
|
||||
|
||||
let html = include_bytes!("minimal.htm");
|
||||
instance.load_html(html, Some("example://minimal.htm"));
|
||||
}
|
||||
|
||||
// events processing
|
||||
use sciter::windowless::{MouseEvent, KeyboardEvent, RenderEvent};
|
||||
use sciter::windowless::{MOUSE_BUTTONS, MOUSE_EVENTS, KEYBOARD_STATES, KEY_EVENTS};
|
||||
|
||||
let mut mouse_button = MOUSE_BUTTONS::NONE;
|
||||
let mut mouse_pos = (0, 0);
|
||||
|
||||
let as_keys = |modifiers: winit::ModifiersState| {
|
||||
let mut keys = 0;
|
||||
if modifiers.ctrl {
|
||||
keys |= 0x01;
|
||||
}
|
||||
if modifiers.shift {
|
||||
keys |= 0x02;
|
||||
}
|
||||
if modifiers.alt {
|
||||
keys |= 0x04;
|
||||
}
|
||||
KEYBOARD_STATES::from(keys)
|
||||
};
|
||||
|
||||
println!("running...");
|
||||
use winit::{Event, WindowEvent};
|
||||
let skip = ();
|
||||
let mut poll_break = false;
|
||||
let startup = std::time::Instant::now();
|
||||
loop {
|
||||
// release CPU a bit, hackish
|
||||
std::thread::sleep(std::time::Duration::from_millis(0));
|
||||
|
||||
// Sciter processes timers and fading effects here
|
||||
handle_message(scwnd, Message::Heartbit {
|
||||
milliseconds: std::time::Instant::now().duration_since(startup).as_millis() as u32,
|
||||
});
|
||||
|
||||
// the actual event loop polling
|
||||
events.poll_events(|event: winit::Event| {
|
||||
match event {
|
||||
Event::WindowEvent { event, window_id: _ } => {
|
||||
match event {
|
||||
WindowEvent::Destroyed => {
|
||||
// never called due to loop break on close
|
||||
println!("destroy");
|
||||
handle_message(scwnd, Message::Destroy);
|
||||
poll_break = true;
|
||||
},
|
||||
|
||||
WindowEvent::CloseRequested => {
|
||||
println!("close");
|
||||
poll_break = true;
|
||||
},
|
||||
|
||||
WindowEvent::Resized(size) => {
|
||||
// println!("{:?}, size: {:?}", event, size);
|
||||
let (width, height): (u32, u32) = size.into();
|
||||
handle_message(scwnd, Message::Size { width, height });
|
||||
skip
|
||||
},
|
||||
|
||||
WindowEvent::Refresh => {
|
||||
|
||||
let on_render = move |bitmap_area: &sciter::types::RECT, bitmap_data: &[u8]|
|
||||
{
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let _ = bitmap_area;
|
||||
let _ = bitmap_data;
|
||||
let _ = window_handle;
|
||||
}
|
||||
|
||||
// Windows-specific bitmap rendering on the window
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use winapi::um::winuser::*;
|
||||
use winapi::um::wingdi::*;
|
||||
use winapi::shared::minwindef::LPVOID;
|
||||
|
||||
let hwnd = match window_handle {
|
||||
raw_window_handle::RawWindowHandle::Windows(data) => data.hwnd as winapi::shared::windef::HWND,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
// NOTE: we use `GetDC` here instead of `BeginPaint`, because the way
|
||||
// winit 0.19 processed the `WM_PAINT` message (it always calls `DefWindowProcW`).
|
||||
|
||||
// let mut ps = PAINTSTRUCT::default();
|
||||
// let hdc = BeginPaint(hwnd, &mut ps as *mut _);
|
||||
|
||||
let hdc = GetDC(hwnd);
|
||||
|
||||
let (w, h) = (bitmap_area.width(), bitmap_area.height());
|
||||
|
||||
let mem_dc = CreateCompatibleDC(hdc);
|
||||
let mem_bm = CreateCompatibleBitmap(hdc, w, h);
|
||||
|
||||
let mut bmi = BITMAPINFO::default();
|
||||
{
|
||||
let mut info = &mut bmi.bmiHeader;
|
||||
info.biSize = std::mem::size_of::<BITMAPINFO>() as u32;
|
||||
info.biWidth = w;
|
||||
info.biHeight = -h;
|
||||
info.biPlanes = 1;
|
||||
info.biBitCount = 32;
|
||||
}
|
||||
|
||||
let old_bm = SelectObject(mem_dc, mem_bm as LPVOID);
|
||||
|
||||
let _copied = StretchDIBits(mem_dc, 0, 0, w, h, 0, 0, w, h, bitmap_data.as_ptr() as *const _, &bmi as *const _, 0, SRCCOPY);
|
||||
let _ok = BitBlt(hdc, 0, 0, w, h, mem_dc, 0, 0, SRCCOPY);
|
||||
|
||||
SelectObject(mem_dc, old_bm);
|
||||
|
||||
// EndPaint(hwnd, &ps as *const _);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
|
||||
// println!("+ {} {}", w, h);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let cb = RenderEvent {
|
||||
layer: None,
|
||||
callback: Box::new(on_render),
|
||||
};
|
||||
|
||||
handle_message(scwnd, Message::RenderTo(cb));
|
||||
skip
|
||||
},
|
||||
|
||||
WindowEvent::Focused(enter) => {
|
||||
println!("focus {}", enter);
|
||||
handle_message(scwnd, Message::Focus { enter });
|
||||
skip
|
||||
},
|
||||
|
||||
WindowEvent::CursorEntered { device_id: _ } => {
|
||||
println!("mouse enter");
|
||||
let event = MouseEvent {
|
||||
event: MOUSE_EVENTS::MOUSE_ENTER,
|
||||
button: mouse_button,
|
||||
modifiers: KEYBOARD_STATES::from(0),
|
||||
pos: sciter::types::POINT {
|
||||
x: mouse_pos.0,
|
||||
y: mouse_pos.1,
|
||||
},
|
||||
};
|
||||
|
||||
handle_message(scwnd, Message::Mouse(event));
|
||||
skip
|
||||
},
|
||||
|
||||
WindowEvent::CursorLeft { device_id: _ } => {
|
||||
println!("mouse leave");
|
||||
let event = MouseEvent {
|
||||
event: MOUSE_EVENTS::MOUSE_LEAVE,
|
||||
button: mouse_button,
|
||||
modifiers: KEYBOARD_STATES::from(0),
|
||||
pos: sciter::types::POINT {
|
||||
x: mouse_pos.0,
|
||||
y: mouse_pos.1,
|
||||
},
|
||||
};
|
||||
|
||||
handle_message(scwnd, Message::Mouse(event));
|
||||
skip
|
||||
},
|
||||
|
||||
WindowEvent::CursorMoved { device_id: _, position, modifiers } => {
|
||||
mouse_pos = position.into();
|
||||
|
||||
let event = MouseEvent {
|
||||
event: MOUSE_EVENTS::MOUSE_MOVE,
|
||||
button: mouse_button,
|
||||
modifiers: as_keys(modifiers),
|
||||
pos: sciter::types::POINT {
|
||||
x: mouse_pos.0,
|
||||
y: mouse_pos.1,
|
||||
},
|
||||
};
|
||||
|
||||
handle_message(scwnd, Message::Mouse(event));
|
||||
skip
|
||||
},
|
||||
|
||||
WindowEvent::MouseInput { device_id: _, state, button, modifiers } => {
|
||||
mouse_button = match button {
|
||||
winit::MouseButton::Left => MOUSE_BUTTONS::MAIN,
|
||||
winit::MouseButton::Right => MOUSE_BUTTONS::PROP,
|
||||
winit::MouseButton::Middle => MOUSE_BUTTONS::MIDDLE,
|
||||
_ => MOUSE_BUTTONS::NONE,
|
||||
};
|
||||
println!("mouse {:?} as {:?}", mouse_button, mouse_pos);
|
||||
|
||||
let event = MouseEvent {
|
||||
event: if state == winit::ElementState::Pressed { MOUSE_EVENTS::MOUSE_DOWN } else { MOUSE_EVENTS::MOUSE_UP },
|
||||
button: mouse_button,
|
||||
modifiers: as_keys(modifiers),
|
||||
pos: sciter::types::POINT {
|
||||
x: mouse_pos.0,
|
||||
y: mouse_pos.1,
|
||||
},
|
||||
};
|
||||
|
||||
handle_message(scwnd, Message::Mouse(event));
|
||||
skip
|
||||
},
|
||||
|
||||
WindowEvent::KeyboardInput { device_id: _, input } => {
|
||||
println!("key {} {}", input.scancode, if input.state == winit::ElementState::Pressed { "down" } else { "up" });
|
||||
|
||||
let event = KeyboardEvent {
|
||||
event: if input.state == winit::ElementState::Pressed { KEY_EVENTS::KEY_DOWN } else { KEY_EVENTS::KEY_UP },
|
||||
code: input.scancode,
|
||||
modifiers: as_keys(input.modifiers),
|
||||
};
|
||||
|
||||
handle_message(scwnd, Message::Keyboard(event));
|
||||
skip
|
||||
},
|
||||
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
|
||||
if poll_break {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
println!("done, quit");
|
||||
}
|
||||
Reference in New Issue
Block a user