use ::{_API};
use capi::sctypes::*;
use platform::{BaseWindow, OsWindow};
use host::{Host, HostHandler};
use dom::{self, event::{EventHandler}};
use crate::Value;
use std::rc::Rc;
pub type Flags = SCITER_CREATE_WINDOW_FLAGS;
pub use capi::scdef::{SCITER_CREATE_WINDOW_FLAGS};
#[derive(Copy, Clone)]
pub enum Options {
SmoothScroll(bool),
FontSmoothing(u8),
TransparentWindow(bool),
AlphaWindow(bool),
DebugMode(bool),
ScriptFeatures(u8),
MainWindow(bool),
LogicalPixel(bool),
}
pub struct Window
{
base: OsWindow,
host: Rc<Host>,
}
#[allow(clippy::new_without_default)]
impl Window {
#[cfg_attr(feature = "windowless", deprecated = "Sciter.Lite doesn't have OS windows in windowless mode.")]
pub fn new() -> Window {
Builder::main_window().create()
}
#[cfg_attr(feature = "windowless", deprecated = "Sciter.Lite doesn't have OS windows in windowless mode.")]
pub fn create(rect: RECT, flags: Flags, parent: Option<HWINDOW>) -> Window {
if cfg!(feature = "windowless")
{
panic!("Sciter.Lite doesn't have OS windows in windowless mode!");
}
let mut base = OsWindow::new();
let hwnd = base.create(rect, flags as UINT, parent.unwrap_or(0 as HWINDOW));
assert!(!hwnd.is_null());
let wnd = Window { base: base, host: Rc::new(Host::attach(hwnd))};
return wnd;
}
pub fn attach(hwnd: HWINDOW) -> Window {
let _ = &OsWindow::new;
assert!(!hwnd.is_null());
Window { base: OsWindow::from(hwnd), host: Rc::new(Host::attach(hwnd)) }
}
#[cfg(all(windows, not(feature = "windowless")))]
pub fn attach_intercepted(hwnd: HWINDOW) -> Window {
assert!(!hwnd.is_null());
#[cfg(target_pointer_width = "64")]
#[link(name="user32")]
extern "system"
{
fn SetWindowLongPtrW(hwnd: HWINDOW, index: i32, new_data: WndProc) -> WndProc;
fn CallWindowProcW(prev: WndProc, hwnd: HWINDOW, msg: UINT, wp: WPARAM, lp: LPARAM) -> LRESULT;
}
#[cfg(target_pointer_width = "32")]
#[link(name="user32")]
extern "system"
{
fn SetWindowLongW(hwnd: HWINDOW, index: i32, new_data: WndProc) -> WndProc;
fn CallWindowProcW(prev: WndProc, hwnd: HWINDOW, msg: UINT, wp: WPARAM, lp: LPARAM) -> LRESULT;
}
#[cfg(target_pointer_width = "64")]
let set_window_proc = SetWindowLongPtrW;
#[cfg(target_pointer_width = "32")]
let set_window_proc = SetWindowLongW;
type WndProc = extern "system" fn (hwnd: HWINDOW, msg: UINT, wp: WPARAM, lp: LPARAM) -> LRESULT;
type PrevProcs = std::collections::HashMap<HWINDOW, WndProc>;
thread_local! {
static PREV_PROC: std::cell::RefCell<PrevProcs> = Default::default();
}
extern "system" fn wnd_proc(hwnd: HWINDOW, msg: UINT, wp: WPARAM, lp: LPARAM) -> LRESULT {
let mut handled = false as BOOL;
let lr = (_API.SciterProcND)(hwnd, msg, wp, lp, &mut handled);
if handled != 0 {
return lr;
}
let mut lr: LRESULT = 0;
PREV_PROC.with(|procs| {
let prev_proc = *procs.borrow().get(&hwnd).expect("An unregistered WindowProc is called somehow.");
lr = unsafe { CallWindowProcW(prev_proc, hwnd, msg, wp, lp) }
});
lr
}
const GWLP_WNDPROC: i32 = -4;
let prev_proc = unsafe { set_window_proc(hwnd, GWLP_WNDPROC, wnd_proc) };
PREV_PROC.with(|procs| {
procs.borrow_mut().insert(hwnd, prev_proc);
});
Window { base: OsWindow::from(hwnd), host: Rc::new(Host::attach(hwnd)) }
}
pub fn get_host(&self) -> Rc<Host> {
self.host.clone()
}
pub fn sciter_handler<Callback: HostHandler + Sized>(&mut self, handler: Callback) {
self.host.setup_callback(handler);
}
pub fn event_handler<Handler: EventHandler>(&mut self, handler: Handler) {
self.host.attach_handler(handler);
}
pub fn archive_handler(&mut self, resource: &[u8]) -> Result<(), ()> {
self.host.register_archive(resource)
}
pub fn register_behavior<Factory>(&mut self, name: &str, factory: Factory)
where
Factory: Fn() -> Box<dyn EventHandler> + 'static
{
self.host.register_behavior(name, factory);
}
pub fn load_file(&mut self, uri: &str) -> bool {
self.host.load_file(uri)
}
pub fn load_html(&mut self, html: &[u8], uri: Option<&str>) -> bool {
self.host.load_html(html, uri)
}
pub fn get_hwnd(&self) -> HWINDOW {
self.base.get_hwnd()
}
pub fn collapse(&self, hide: bool) {
self.base.collapse(hide)
}
pub fn expand(&self, maximize: bool) {
self.base.expand(maximize)
}
pub fn dismiss(&self) {
self.base.dismiss()
}
pub fn set_title(&mut self, title: &str) {
self.base.set_title(title)
}
pub fn get_title(&self) -> String {
self.base.get_title()
}
pub fn set_options(&self, options: Options) -> Result<(), ()> {
use capi::scdef::SCITER_RT_OPTIONS::*;
use self::Options::*;
let (option, value) = match options {
SmoothScroll(enable) => (SCITER_SMOOTH_SCROLL, enable as usize),
FontSmoothing(technology) => (SCITER_FONT_SMOOTHING, technology as usize),
TransparentWindow(enable) => (SCITER_TRANSPARENT_WINDOW, enable as usize),
AlphaWindow(enable) => (SCITER_ALPHA_WINDOW, enable as usize),
MainWindow(enable) => (SCITER_SET_MAIN_WINDOW, enable as usize),
DebugMode(enable) => (SCITER_SET_DEBUG_MODE, enable as usize),
ScriptFeatures(mask) => (SCITER_SET_SCRIPT_RUNTIME_FEATURES, mask as usize),
LogicalPixel(enable) => (SCITER_SET_PX_AS_DIP, enable as usize),
};
let ok = (_API.SciterSetOption)(self.get_hwnd(), option, value);
if ok != 0 {
Ok(())
} else {
Err(())
}
}
pub fn set_variable(&self, path: &str, value: Value) -> dom::Result<()> {
let ws = s2u!(path);
let ok = (_API.SciterSetVariable)(self.get_hwnd(), ws.as_ptr(), value.as_cptr());
if ok == dom::SCDOM_RESULT::OK {
Ok(())
} else {
Err(ok)
}
}
pub fn get_variable(&self, path: &str) -> dom::Result<Value> {
let ws = s2u!(path);
let mut value = Value::new();
let ok = (_API.SciterGetVariable)(self.get_hwnd(), ws.as_ptr(), value.as_mut_ptr());
if ok == dom::SCDOM_RESULT::OK {
Ok(value)
} else {
Err(ok)
}
}
pub fn run_app(self) {
self.base.expand(false);
self.base.run_app();
}
pub fn run_loop(self) {
self.base.run_app();
}
pub fn quit_app(&self) {
self.base.quit_app()
}
}
#[derive(Clone, Copy)]
pub struct Rectangle {
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32
}
#[derive(Default)]
pub struct Builder {
flags: Flags,
rect: RECT,
parent: Option<HWINDOW>,
}
impl Builder {
pub fn main_window() -> Self {
Builder::main()
.resizeable()
.closeable()
.with_title()
}
pub fn popup_window() -> Self {
Builder::popup()
.closeable()
.with_title()
}
pub fn child_window() -> Self {
Builder::with_flags(SCITER_CREATE_WINDOW_FLAGS::SW_CHILD)
}
pub fn none() -> Self {
Builder::with_flags(SCITER_CREATE_WINDOW_FLAGS::SW_CHILD) }
pub fn with_flags(flags: Flags) -> Self {
Self {
flags,
..Default::default()
}
}
pub fn main() -> Self {
Builder::with_flags(SCITER_CREATE_WINDOW_FLAGS::SW_MAIN)
}
pub fn popup() -> Self {
Builder::with_flags(SCITER_CREATE_WINDOW_FLAGS::SW_POPUP)
}
pub fn tool() -> Self {
Builder::with_flags(SCITER_CREATE_WINDOW_FLAGS::SW_TOOL)
}
pub fn with_parent(mut self, parent: HWINDOW) -> Self {
self.parent = Some(parent);
self
}
pub fn with_size(mut self, size: (i32, i32)) -> Self {
self.rect.right = self.rect.left + size.0;
self.rect.bottom = self.rect.top + size.1;
self
}
pub fn with_pos(mut self, position: (i32, i32)) -> Self {
let size = self.rect.size();
self.rect.left = position.0;
self.rect.top = position.1;
self.rect.right = position.0 + size.cx;
self.rect.bottom = position.1 + size.cy;
self
}
pub fn with_rect(mut self, rect: Rectangle) -> Self {
self.rect = RECT {
left: rect.x,
top: rect.y,
right: rect.x + rect.width,
bottom: rect.y + rect.height,
};
self
}
pub fn with_title(self) -> Self {
self.or(SCITER_CREATE_WINDOW_FLAGS::SW_TITLEBAR)
}
pub fn resizeable(self) -> Self {
self.or(SCITER_CREATE_WINDOW_FLAGS::SW_RESIZEABLE)
}
pub fn fixed(self) -> Self {
self.and(SCITER_CREATE_WINDOW_FLAGS::SW_RESIZEABLE)
}
pub fn closeable(self) -> Self {
self.or(SCITER_CREATE_WINDOW_FLAGS::SW_CONTROLS)
}
pub fn glassy(self) -> Self {
self.or(SCITER_CREATE_WINDOW_FLAGS::SW_GLASSY)
}
pub fn alpha(self) -> Self {
self.or(SCITER_CREATE_WINDOW_FLAGS::SW_ALPHA)
}
pub fn debug(self) -> Self {
self.or(SCITER_CREATE_WINDOW_FLAGS::SW_ENABLE_DEBUG)
}
fn or(mut self, flag: Flags) -> Self {
self.flags = self.flags | flag;
self
}
fn and(mut self, flag: Flags) -> Self {
let masked = self.flags as u32 & !(flag as u32);
self.flags = unsafe { ::std::mem::transmute(masked) };
self
}
#[cfg_attr(feature = "windowless", deprecated = "Sciter.Lite doesn't have OS windows in windowless mode.")]
pub fn create(self) -> Window {
Window::create(self.rect, self.flags, self.parent)
}
}