use winapi::shared::minwindef::{WPARAM, LPARAM};
use winapi::um::winuser::{WS_VSCROLL, WS_HSCROLL, ES_AUTOVSCROLL, ES_AUTOHSCROLL, WS_VISIBLE, WS_DISABLED, WS_TABSTOP};
use crate::win32::window_helper as wh;
use crate::{Font, NwgError};
use super::{ControlBase, ControlHandle};
use std::ops::Range;
const NOT_BOUND: &'static str = "TextBox is not yet bound to a winapi object";
const BAD_HANDLE: &'static str = "INTERNAL ERROR: TextBox handle is not HWND!";
bitflags! {
pub struct TextBoxFlags: u32 {
const VSCROLL = WS_VSCROLL;
const HSCROLL = WS_HSCROLL;
const AUTOVSCROLL = ES_AUTOVSCROLL;
const AUTOHSCROLL = ES_AUTOHSCROLL;
const VISIBLE = WS_VISIBLE;
const DISABLED = WS_DISABLED;
const TAB_STOP = WS_TABSTOP;
}
}
#[derive(Default, PartialEq, Eq)]
pub struct TextBox {
pub handle: ControlHandle
}
impl TextBox {
pub fn builder<'a>() -> TextBoxBuilder<'a> {
TextBoxBuilder {
text: "",
size: (100, 25),
position: (0, 0),
flags: None,
ex_flags: 0,
limit: 0,
readonly: false,
focus: false,
font: None,
parent: None
}
}
pub fn font(&self) -> Option<Font> {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
let font_handle = wh::get_window_font(handle);
if font_handle.is_null() {
None
} else {
Some(Font { handle: font_handle })
}
}
pub fn set_font(&self, font: Option<&Font>) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::set_window_font(handle, font.map(|f| f.handle), true); }
}
pub fn limit(&self) -> u32 {
use winapi::um::winuser::EM_GETLIMITTEXT;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::send_message(handle, EM_GETLIMITTEXT as u32, 0, 0) as u32
}
pub fn set_limit(&self, limit: usize) {
use winapi::um::winuser::EM_SETLIMITTEXT;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::send_message(handle, EM_SETLIMITTEXT as u32, limit, 0);
}
pub fn modified(&self) -> bool {
use winapi::um::winuser::EM_GETMODIFY;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::send_message(handle, EM_GETMODIFY as u32, 0, 0) != 0
}
pub fn set_modified(&self, e: bool) {
use winapi::um::winuser::EM_SETMODIFY;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::send_message(handle, EM_SETMODIFY as u32, e as usize, 0);
}
pub fn undo(&self) {
use winapi::um::winuser::EM_UNDO;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::send_message(handle, EM_UNDO as u32, 0, 0);
}
pub fn selection(&self) -> Range<u32> {
use winapi::um::winuser::EM_GETSEL;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
let (mut out1, mut out2) = (0u32, 0u32);
let (ptr1, ptr2) = (&mut out1 as *mut u32, &mut out2 as *mut u32);
wh::send_message(handle, EM_GETSEL as u32, ptr1 as WPARAM, ptr2 as LPARAM);
Range { start: out1 as u32, end: out2 as u32 }
}
pub fn set_selection(&self, r: Range<u32>) {
use winapi::um::winuser::EM_SETSEL;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::send_message(handle, EM_SETSEL as u32, r.start as usize, r.end as isize);
}
pub fn len(&self) -> u32 {
use winapi::um::winuser::EM_LINELENGTH;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::send_message(handle, EM_LINELENGTH as u32, 0, 0) as u32
}
pub fn readonly(&self) -> bool {
use winapi::um::winuser::ES_READONLY;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::get_style(handle) & ES_READONLY == ES_READONLY
}
pub fn set_readonly(&self, r: bool) {
use winapi::um::winuser::EM_SETREADONLY;
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
wh::send_message(handle, EM_SETREADONLY as u32, r as WPARAM, 0);
}
pub fn clear(&self) {
self.set_text("");
}
pub fn focus(&self) -> bool {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::get_focus(handle) }
}
pub fn set_focus(&self) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::set_focus(handle); }
}
pub fn enabled(&self) -> bool {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::get_window_enabled(handle) }
}
pub fn set_enabled(&self, v: bool) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::set_window_enabled(handle, v) }
}
pub fn visible(&self) -> bool {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::get_window_visibility(handle) }
}
pub fn set_visible(&self, v: bool) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::set_window_visibility(handle, v) }
}
pub fn size(&self) -> (u32, u32) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::get_window_size(handle) }
}
pub fn set_size(&self, x: u32, y: u32) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::set_window_size(handle, x, y, false) }
}
pub fn position(&self) -> (i32, i32) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::get_window_position(handle) }
}
pub fn set_position(&self, x: i32, y: i32) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::set_window_position(handle, x, y) }
}
pub fn text(&self) -> String {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::get_window_text(handle) }
}
pub fn set_text<'a>(&self, v: &'a str) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let handle = self.handle.hwnd().expect(BAD_HANDLE);
unsafe { wh::set_window_text(handle, v) }
}
pub fn class_name(&self) -> &'static str {
"EDIT"
}
pub fn flags(&self) -> u32 {
WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_TABSTOP
}
pub fn forced_flags(&self) -> u32 {
use winapi::um::winuser::{WS_BORDER, WS_CHILD, ES_MULTILINE, ES_WANTRETURN};
WS_BORDER | WS_CHILD | ES_MULTILINE | ES_WANTRETURN
}
}
impl Drop for TextBox {
fn drop(&mut self) {
self.handle.destroy();
}
}
pub struct TextBoxBuilder<'a> {
text: &'a str,
size: (i32, i32),
position: (i32, i32),
flags: Option<TextBoxFlags>,
ex_flags: u32,
limit: usize,
readonly: bool,
focus: bool,
font: Option<&'a Font>,
parent: Option<ControlHandle>
}
impl<'a> TextBoxBuilder<'a> {
pub fn flags(mut self, flags: TextBoxFlags) -> TextBoxBuilder<'a> {
self.flags = Some(flags);
self
}
pub fn ex_flags(mut self, flags: u32) -> TextBoxBuilder<'a> {
self.ex_flags = flags;
self
}
pub fn text(mut self, text: &'a str) -> TextBoxBuilder<'a> {
self.text = text;
self
}
pub fn size(mut self, size: (i32, i32)) -> TextBoxBuilder<'a> {
self.size = size;
self
}
pub fn position(mut self, pos: (i32, i32)) -> TextBoxBuilder<'a> {
self.position = pos;
self
}
pub fn limit(mut self, limit: usize) -> TextBoxBuilder<'a> {
self.limit = limit;
self
}
pub fn readonly(mut self, read: bool) -> TextBoxBuilder<'a> {
self.readonly = read;
self
}
pub fn focus(mut self, focus: bool) -> TextBoxBuilder<'a> {
self.focus = focus;
self
}
pub fn font(mut self, font: Option<&'a Font>) -> TextBoxBuilder<'a> {
self.font = font;
self
}
pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> TextBoxBuilder<'a> {
self.parent = Some(p.into());
self
}
pub fn build(self, out: &mut TextBox) -> Result<(), NwgError> {
let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
let parent = match self.parent {
Some(p) => Ok(p),
None => Err(NwgError::no_parent("TextBox"))
}?;
*out = Default::default();
out.handle = ControlBase::build_hwnd()
.class_name(out.class_name())
.forced_flags(out.forced_flags())
.flags(flags)
.ex_flags(self.ex_flags)
.size(self.size)
.position(self.position)
.text(self.text)
.parent(Some(parent))
.build()?;
if self.limit > 0 {
out.set_limit(self.limit);
}
if self.readonly {
out.set_readonly(self.readonly);
}
if self.focus {
out.set_focus();
}
if self.font.is_some() {
out.set_font(self.font);
} else {
out.set_font(Font::global_default().as_ref());
}
Ok(())
}
}