diff --git a/examples/Cargo.toml b/examples/Cargo.toml index c0308eb..31045ab 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,7 +5,11 @@ edition = "2021" [dependencies] tipc = { path = "../tipc/" } -tmui = { path = "../tmui/", features = ["font_awesome", "win_popup"] } +tmui = { path = "../tmui/", features = [ + "font_awesome", + "win_tooltip", + "win_dialog", +] } widestring = "1.0.2" log = "0.4" diff --git a/examples/border/border_with_child.rs b/examples/border/border_with_child.rs new file mode 100644 index 0000000..68d501b --- /dev/null +++ b/examples/border/border_with_child.rs @@ -0,0 +1,49 @@ +use log::info; +use tmui::{ + prelude::*, + tlib::object::{ObjectImpl, ObjectSubclass}, + widget::WidgetImpl, +}; + +#[extends(Widget, Layout(HBox))] +#[derive(Childrenable)] +pub struct BorderWithChild { + #[children] + widget_left: Tr, + #[children] + widget_right: Tr, +} + +impl ObjectSubclass for BorderWithChild { + const NAME: &'static str = "BorderWithChild"; +} + +impl ObjectImpl for BorderWithChild { + fn initialize(&mut self) { + self.set_background(Color::GREY_LIGHT); + self.set_halign(Align::Center); + self.enable_bubble(EventBubble::MOUSE_MOVE); + + self.set_margin_top(5); + self.set_border_radius(6.); + + self.widget_left.width_request(25); + self.widget_left.height_request(25); + + self.widget_right.width_request(25); + self.widget_right.height_request(25); + self.widget_right.set_mouse_tracking(true); + } +} + +impl WidgetImpl for BorderWithChild { + fn on_mouse_enter(&mut self, _: &MouseEvent) { + info!("Mouse entered."); + self.set_background(Color::GREY_MEDIUM); + } + + fn on_mouse_leave(&mut self, _: &MouseEvent) { + info!("Mouse leaved."); + self.set_background(Color::GREY_LIGHT); + } +} diff --git a/examples/border/main.rs b/examples/border/main.rs index f250885..8c8733e 100644 --- a/examples/border/main.rs +++ b/examples/border/main.rs @@ -1,3 +1,6 @@ +pub mod border_with_child; + +use border_with_child::BorderWithChild; use tmui::{application::Application, application_window::ApplicationWindow, prelude::*}; fn main() { @@ -15,6 +18,8 @@ fn main() { } fn build_ui(window: &mut ApplicationWindow) { + let mut vbox = VBox::new(); + let mut hbox = HBox::new(); let mut widget1 = Widget::new_alloc(); let mut widget2 = Widget::new_alloc(); @@ -47,5 +52,11 @@ fn build_ui(window: &mut ApplicationWindow) { hbox.height_request(400); hbox.set_background(Color::RED); - window.child(hbox); + vbox.set_halign(Align::Center); + vbox.set_valign(Align::Center); + vbox.add_child(hbox); + vbox.set_content_halign(Align::Center); + vbox.add_child(BorderWithChild::new_alloc()); + + window.child(vbox); } diff --git a/examples/child_window/main.rs b/examples/child_window/main.rs index 0f7f89a..38d7840 100644 --- a/examples/child_window/main.rs +++ b/examples/child_window/main.rs @@ -2,6 +2,7 @@ use tlib::figure::OptionSize; use tmui::{ application::Application, application_window::ApplicationWindow, + graphics::styles::Styles, label::Label, prelude::*, tooltip::Tooltip, @@ -48,6 +49,11 @@ fn build_ui(window: &mut ApplicationWindow) { window.register_mouse_released(|_, evt| { let mut pos: Point = evt.position().into(); pos.offset(-100, -100); - Tooltip::show("Test tooltip overlap", pos, OptionSize::none(), None); + Tooltip::show( + "Test tooltip overlap", + pos, + OptionSize::none(), + Some(Styles::default().with_border(Border::default().with_border_radius(6.))), + ); }); } diff --git a/examples/input_element/holder.rs b/examples/input_element/holder.rs index 71f016f..6c943e2 100644 --- a/examples/input_element/holder.rs +++ b/examples/input_element/holder.rs @@ -54,7 +54,6 @@ impl ObjectSubclass for Holder { impl ObjectImpl for Holder { fn construct(&mut self) { - Select::::new_alloc(); self.parent_construct(); self.add_popup(InputPopup::new().to_dyn_popup_tr()); } diff --git a/tmui/src/application_window.rs b/tmui/src/application_window.rs index 9b28cf3..f3b8200 100644 --- a/tmui/src/application_window.rs +++ b/tmui/src/application_window.rs @@ -678,7 +678,7 @@ impl ApplicationWindow { for (_, overlaid) in self.overlaids.iter_mut() { let overlaid = nonnull_mut!(overlaid); if let Some(popup) = cast_mut!(overlaid as PopupImpl) { - if !popup.hide_on_click() { + if !popup.hide_on_click() || evt.mouse_button() != popup.click_hide_button() { continue; } if popup.handle_global_mouse_pressed(evt) { diff --git a/tmui/src/graphics/border.rs b/tmui/src/graphics/border.rs index 7ec7cac..16cf7af 100644 --- a/tmui/src/graphics/border.rs +++ b/tmui/src/graphics/border.rs @@ -40,6 +40,48 @@ impl Border { } } + #[inline] + pub fn with_style(mut self, style: BorderStyle) -> Self { + self.style = style; + self + } + + #[inline] + pub fn with_width(mut self, width: f32) -> Self { + self.width = (width, width, width, width); + self + } + + #[inline] + pub fn with_width_sep(mut self, top: f32, right: f32, bottom: f32, left: f32) -> Self { + self.width = (top, right, bottom, left); + self + } + + #[inline] + pub fn with_color(mut self, color: Color) -> Self { + self.border_color = (color, color, color, color); + self + } + + #[inline] + pub fn with_color_sep(mut self, top: Color, right: Color, bottom: Color, left: Color) -> Self { + self.border_color = (top, right, bottom, left); + self + } + + #[inline] + pub fn with_border_radius(mut self, radius: f32) -> Self { + self.border_radius = (radius, radius, radius, radius); + self + } + + #[inline] + pub fn with_border_radius_sep(mut self, lt: f32, rt: f32, rb: f32, lb: f32) -> Self { + self.border_radius = (lt, rt, rb, lb); + self + } + pub(crate) fn render(&self, painter: &mut Painter, geometry: FRect) { painter.save_pen(); @@ -284,6 +326,7 @@ impl Border { geometry.offset(left / 2., top / 2.); geometry.set_width(geometry.width() - right); geometry.set_height(geometry.height() - bottom); + painter.set_antialiasing(true); painter.draw_round_rect(geometry, self.border_radius); painter.reset(); @@ -341,11 +384,11 @@ impl Border { let (start_width, mid_width, end_width) = (left, (left + top) / 2., top); if left > 0. { painter.set_color(self.border_color.3); - painter.draw_varying_arc(lt, 180., 45., start_width, mid_width, 8); + painter.draw_varying_arc(lt, 180., 45., start_width, mid_width, 16); } if top > 0. { painter.set_color(self.border_color.0); - painter.draw_varying_arc(lt, 225., 45., mid_width, end_width, 8); + painter.draw_varying_arc(lt, 225., 45., mid_width, end_width, 16); } let dimension = 2. * self.border_radius.1; @@ -358,11 +401,11 @@ impl Border { let (start_width, mid_width, end_width) = (top, (top + right) / 2., right); if top > 0. { painter.set_color(self.border_color.0); - painter.draw_varying_arc(rt, 270., 45., start_width, mid_width, 8); + painter.draw_varying_arc(rt, 270., 45., start_width, mid_width, 16); } if right > 0. { painter.set_color(self.border_color.1); - painter.draw_varying_arc(rt, 315., 45., mid_width, end_width, 8); + painter.draw_varying_arc(rt, 315., 45., mid_width, end_width, 16); } let dimension = 2. * self.border_radius.2; @@ -375,11 +418,11 @@ impl Border { let (start_width, mid_width, end_width) = (right, (bottom + right) / 2., bottom); if right > 0. { painter.set_color(self.border_color.1); - painter.draw_varying_arc(rb, 0., 45., start_width, mid_width, 8); + painter.draw_varying_arc(rb, 0., 45., start_width, mid_width, 16); } if bottom > 0. { painter.set_color(self.border_color.2); - painter.draw_varying_arc(rb, 45., 45., mid_width, end_width, 8); + painter.draw_varying_arc(rb, 45., 45., mid_width, end_width, 16); } let dimension = 2. * self.border_radius.3; @@ -392,11 +435,11 @@ impl Border { let (start_width, mid_width, end_width) = (bottom, (bottom + left) / 2., left); if bottom > 0. { painter.set_color(self.border_color.2); - painter.draw_varying_arc(lb, 90., 45., start_width, mid_width, 8); + painter.draw_varying_arc(lb, 90., 45., start_width, mid_width, 16); } if left > 0. { painter.set_color(self.border_color.3); - painter.draw_varying_arc(lb, 135., 45., mid_width, end_width, 8); + painter.draw_varying_arc(lb, 135., 45., mid_width, end_width, 16); } painter.reset(); diff --git a/tmui/src/input/dialog.rs b/tmui/src/input/dialog.rs index f7392de..6ffff6b 100644 --- a/tmui/src/input/dialog.rs +++ b/tmui/src/input/dialog.rs @@ -237,6 +237,8 @@ impl InputDialog { if let Some(styles) = styles { input.set_styles(styles); }; + let radius = input.border_ref().border_radius; + self.set_border_radius_sep(radius.0, radius.1, radius.2, radius.3); self.switch_index(idx); self.current = input_type; diff --git a/tmui/src/popup.rs b/tmui/src/popup.rs index 50385e4..8d8bb8b 100644 --- a/tmui/src/popup.rs +++ b/tmui/src/popup.rs @@ -4,7 +4,7 @@ use crate::{ widget::WidgetImpl, }; use std::ptr::NonNull; -use tlib::{events::MouseEvent, nonnull_mut, nonnull_ref}; +use tlib::{events::MouseEvent, namespace::MouseButton, nonnull_mut, nonnull_ref}; #[extends(Widget)] #[cfg(win_popup)] @@ -150,6 +150,12 @@ pub trait PopupImpl: WidgetImpl + PopupExt + Overlaid { true } + /// The mouse button of mouse to clicking hide the component. + #[inline] + fn click_hide_button(&self) -> MouseButton { + MouseButton::LeftButton + } + /// If true, popup will move postion by mouse dragging. /// /// Default value is [`false`] diff --git a/tmui/src/runtime/wed.rs b/tmui/src/runtime/wed.rs index bb1451a..a051a80 100644 --- a/tmui/src/runtime/wed.rs +++ b/tmui/src/runtime/wed.rs @@ -161,6 +161,7 @@ pub(crate) fn win_evt_dispatch(window: &mut ApplicationWindow, evt: Event) -> Op } window.check_mouse_leave(&pos, &evt); + let mut mouse_move_handled = false; for (_id, widget_opt) in widgets_map.iter_mut() { let widget = nonnull_mut!(widget_opt); @@ -177,8 +178,12 @@ pub(crate) fn win_evt_dispatch(window: &mut ApplicationWindow, evt: Event) -> Op if !widget.visible() { continue; } + window.check_mouse_enter(widget, &pos, &evt); + if mouse_move_handled { + continue; + } let widget_position = widget.map_to_widget(&pos); if widget.point_effective(&evt.position().into()) { @@ -237,9 +242,9 @@ pub(crate) fn win_evt_dispatch(window: &mut ApplicationWindow, evt: Event) -> Op widget.on_mouse_move(evt.as_ref()); if widget.super_type().is_a(SharedWidget::static_type()) { - event = Some(evt); + event = Some(evt.clone()); } - break; + mouse_move_handled = true; } } diff --git a/tmui/src/widget/mod.rs b/tmui/src/widget/mod.rs index 80c427e..f373c7f 100644 --- a/tmui/src/widget/mod.rs +++ b/tmui/src/widget/mod.rs @@ -548,7 +548,10 @@ impl ElementImpl for self.clip_child_region(&mut painter); } if let Some(parent) = self.get_parent_ref() { - if cast!(parent as ContainerImpl).is_some() { + if parent.border_ref().should_draw_radius() { + let radius = parent.border_ref().border_radius; + painter.clip_round_rect_global(parent.rect(), radius, ClipOp::Intersect); + } else { painter.clip_rect_global(parent.contents_rect(None), ClipOp::Intersect); } } diff --git a/tmui/src/widget/win_widget.rs b/tmui/src/widget/win_widget.rs index 0bf6716..3e5d38b 100644 --- a/tmui/src/widget/win_widget.rs +++ b/tmui/src/widget/win_widget.rs @@ -55,6 +55,8 @@ pub(crate) fn handle_win_widget_create(win_widget: &mut dyn WinWidget, inner: bo window.map_to_client(&rect.top_left()) }; + let radius = win_widget.border_ref().border_radius; + let child_proc_fn = win_widget.child_process_fn(); window.create_window( WindowBuilder::new() @@ -74,6 +76,8 @@ pub(crate) fn handle_win_widget_create(win_widget: &mut dyn WinWidget, inner: bo .win_widget_id(win_widget.id()) .on_activate(move |win| { win.set_transparency(0); + win.set_border_radius_sep(radius.0, radius.1, radius.2, radius.3); + child_proc_fn(win); }), )