Skip to content

Commit 38a456c

Browse files
authored
Merge pull request #95 from compio-rs/dev/tabviewitem-parent
feat: don't require parent on initializing `TabViewItem`
2 parents 5c959f5 + 72575c9 commit 38a456c

File tree

18 files changed

+128
-86
lines changed

18 files changed

+128
-86
lines changed

winio-ui-app-kit/src/ui/tab_view.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use winio_callback::Callback;
1010
use winio_handle::{AsContainer, BorrowedContainer};
1111
use winio_primitive::{Point, Size};
1212

13-
use crate::{GlobalRuntime, Result, catch, from_cgsize, from_nsstring, ui::Widget};
13+
use crate::{Error, GlobalRuntime, Result, catch, from_cgsize, from_nsstring, ui::Widget};
1414

1515
#[derive(Debug)]
1616
pub struct TabView {
@@ -154,10 +154,10 @@ pub struct TabViewItem {
154154
}
155155

156156
impl TabViewItem {
157-
pub fn new(parent: &TabView) -> Result<Self> {
157+
pub fn new() -> Result<Self> {
158+
let mtm = MainThreadMarker::new().ok_or(Error::NotMainThread)?;
158159
catch(|| {
159160
let item = NSTabViewItem::new();
160-
let mtm = parent.view.mtm();
161161
let view = NSView::new(mtm);
162162
item.setView(Some(&view));
163163
Self { item, view }

winio-ui-gtk/src/ui/tab_view.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ pub struct TabViewItem {
102102
}
103103

104104
impl TabViewItem {
105-
pub fn new(_parent: &TabView) -> Result<Self> {
105+
pub fn new() -> Result<Self> {
106106
let swindow = gtk4::ScrolledWindow::new();
107107
swindow.set_hscrollbar_policy(gtk4::PolicyType::External);
108108
swindow.set_vscrollbar_policy(gtk4::PolicyType::External);

winio-ui-qt/src/ui/tab_view.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub struct TabViewItem {
112112

113113
#[inherit_methods(from = "self.view")]
114114
impl TabViewItem {
115-
pub fn new(_parent: &TabView) -> Result<Self> {
115+
pub fn new() -> Result<Self> {
116116
let view = View::new_standalone()?;
117117
Ok(Self {
118118
view,

winio-ui-win32/src/ui/tab_view.rs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,21 @@ use std::{
66

77
use compio::driver::syscall;
88
use inherit_methods_macro::inherit_methods;
9+
use windows::core::HRESULT;
910
use windows_sys::{
10-
Win32::UI::{
11-
Controls::{
12-
TCIF_TEXT, TCITEMW, TCM_ADJUSTRECT, TCM_DELETEALLITEMS, TCM_DELETEITEM, TCM_GETCURSEL,
13-
TCM_GETITEMCOUNT, TCM_INSERTITEMW, TCM_SETCURSEL, TCM_SETITEMW, TCN_SELCHANGE,
14-
TCS_TABS, WC_TABCONTROLW,
15-
},
16-
WindowsAndMessaging::{
17-
GetClientRect, GetParent, MoveWindow, SW_HIDE, SW_SHOW, SendMessageW, ShowWindow,
18-
WM_NOTIFY, WS_CHILD, WS_CLIPCHILDREN, WS_EX_CONTROLPARENT, WS_TABSTOP, WS_VISIBLE,
11+
Win32::{
12+
Foundation::ERROR_ALREADY_EXISTS,
13+
UI::{
14+
Controls::{
15+
TCIF_TEXT, TCITEMW, TCM_ADJUSTRECT, TCM_DELETEALLITEMS, TCM_DELETEITEM,
16+
TCM_GETCURSEL, TCM_GETITEMCOUNT, TCM_INSERTITEMW, TCM_SETCURSEL, TCM_SETITEMW,
17+
TCN_SELCHANGE, TCS_TABS, WC_TABCONTROLW,
18+
},
19+
WindowsAndMessaging::{
20+
GetClientRect, GetParent, HWND_MESSAGE, MoveWindow, SW_HIDE, SW_SHOW, SendMessageW,
21+
SetParent, ShowWindow, WM_NOTIFY, WS_CHILD, WS_CLIPCHILDREN, WS_EX_CONTROLPARENT,
22+
WS_TABSTOP, WS_VISIBLE,
23+
},
1924
},
2025
},
2126
w,
@@ -24,7 +29,7 @@ use winio_handle::{AsContainer, AsWidget, BorrowedContainer};
2429
use winio_primitive::{Point, Size};
2530
use winio_ui_windows_common::children_refresh_dark_mode;
2631

27-
use crate::{Result, View, Widget, WindowMessageNotify, ui::with_u16c};
32+
use crate::{Error, Result, View, Widget, WindowMessageNotify, ui::with_u16c};
2833

2934
#[derive(Debug)]
3035
pub struct TabView {
@@ -164,6 +169,21 @@ impl TabView {
164169
}
165170

166171
pub fn insert(&mut self, i: usize, item: &TabViewItem) -> Result<()> {
172+
if item.inner.borrow().index.is_some() {
173+
return Err(Error::from_hresult(HRESULT::from_win32(
174+
ERROR_ALREADY_EXISTS,
175+
)));
176+
}
177+
let item_hwnd = item.as_container().as_win32();
178+
let previous_parent = unsafe { GetParent(item_hwnd) };
179+
let new_parent = self.as_widget().as_win32();
180+
if previous_parent == new_parent {
181+
return Err(Error::from_hresult(HRESULT::from_win32(
182+
ERROR_ALREADY_EXISTS,
183+
)));
184+
}
185+
unsafe { SetParent(item_hwnd, new_parent) };
186+
167187
self.views.insert(i, item.clone());
168188
{
169189
let mut inner = item.inner.borrow_mut();
@@ -194,7 +214,10 @@ impl TabView {
194214
let cur = self.selection()?;
195215
let need_reselect = cur == Some(i);
196216
self.handle.send_message(TCM_DELETEITEM, i, 0);
197-
self.views.remove(i);
217+
let item = self.views.remove(i);
218+
let mut inner = item.inner.borrow_mut();
219+
unsafe { SetParent(inner.view.as_widget().as_win32(), HWND_MESSAGE) };
220+
inner.index = None;
198221
self.reset_indices();
199222
if need_reselect {
200223
self.set_selection(0)?;
@@ -213,7 +236,9 @@ impl TabView {
213236
pub fn clear(&mut self) -> Result<()> {
214237
self.handle.send_message(TCM_DELETEALLITEMS, 0, 0);
215238
for item in self.views.drain(..) {
216-
item.inner.borrow_mut().index = None;
239+
let mut inner = item.inner.borrow_mut();
240+
unsafe { SetParent(inner.view.as_widget().as_win32(), HWND_MESSAGE) };
241+
inner.index = None;
217242
}
218243
Ok(())
219244
}
@@ -234,10 +259,10 @@ pub struct TabViewItem {
234259
}
235260

236261
impl TabViewItem {
237-
pub fn new(parent: &TabView) -> Result<Self> {
262+
pub fn new() -> Result<Self> {
238263
Ok(Self {
239264
inner: Rc::new(RefCell::new(TabViewItemInner {
240-
view: View::new_hidden(parent.as_widget().as_win32())?,
265+
view: View::new_hidden(HWND_MESSAGE)?,
241266
title: String::new(),
242267
index: None,
243268
})),

winio-ui-winui/src/ui/tab_view.rs

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::rc::Rc;
1+
use std::{cell::RefCell, rc::Rc};
22

33
use compio_log::error;
44
use inherit_methods_macro::inherit_methods;
@@ -16,6 +16,7 @@ pub struct TabView {
1616
on_select: SendWrapper<Rc<Callback>>,
1717
handle: Widget,
1818
view: MUXC::TabView,
19+
views: Vec<TabViewItem>,
1920
}
2021

2122
#[inherit_methods(from = "self.handle")]
@@ -37,6 +38,7 @@ impl TabView {
3738
on_select,
3839
handle: Widget::new(parent, view.cast()?)?,
3940
view,
41+
views: vec![],
4042
})
4143
}
4244

@@ -79,17 +81,20 @@ impl TabView {
7981
}
8082

8183
pub fn insert(&mut self, i: usize, item: &TabViewItem) -> Result<()> {
82-
self.view.TabItems()?.InsertAt(i as _, &item.item)?;
84+
self.view.TabItems()?.InsertAt(i as _, &item.inner.item)?;
85+
item.inner.parent.replace(Some(self.view.clone()));
86+
self.views.insert(i, item.clone());
8387
self.view
8488
.Measure(Size::new(f64::INFINITY, f64::INFINITY).to_native())?;
85-
if self.len()? == 1 {
89+
if self.len()? == 1 && self.selection()?.is_none() {
8690
self.set_selection(0)?;
8791
}
8892
Ok(())
8993
}
9094

9195
pub fn remove(&mut self, i: usize) -> Result<()> {
9296
self.view.TabItems()?.RemoveAt(i as _)?;
97+
self.views.remove(i).inner.parent.replace(None);
9398
Ok(())
9499
}
95100

@@ -103,22 +108,30 @@ impl TabView {
103108

104109
pub fn clear(&mut self) -> Result<()> {
105110
self.view.TabItems()?.Clear()?;
111+
for item in self.views.drain(..) {
112+
item.inner.parent.replace(None);
113+
}
106114
Ok(())
107115
}
108116
}
109117

110118
winio_handle::impl_as_widget!(TabView, handle);
111119

112120
#[derive(Debug)]
113-
pub struct TabViewItem {
114-
parent: MUXC::TabView,
121+
struct TabViewInner {
122+
parent: RefCell<Option<MUXC::TabView>>,
115123
item: MUXC::TabViewItem,
116124
canvas: MUXC::Canvas,
117125
text: MUXC::TextBlock,
118126
}
119127

128+
#[derive(Debug, Clone)]
129+
pub struct TabViewItem {
130+
inner: Rc<TabViewInner>,
131+
}
132+
120133
impl TabViewItem {
121-
pub fn new(parent: &TabView) -> Result<Self> {
134+
pub fn new() -> Result<Self> {
122135
let item = MUXC::TabViewItem::new()?;
123136
item.SetHorizontalAlignment(HorizontalAlignment::Stretch)?;
124137
item.SetVerticalAlignment(VerticalAlignment::Stretch)?;
@@ -130,32 +143,38 @@ impl TabViewItem {
130143
canvas.SetVerticalAlignment(VerticalAlignment::Stretch)?;
131144
item.SetContent(&canvas)?;
132145
Ok(Self {
133-
parent: parent.view.clone(),
134-
item,
135-
canvas,
136-
text,
146+
inner: Rc::new(TabViewInner {
147+
parent: RefCell::new(None),
148+
item,
149+
canvas,
150+
text,
151+
}),
137152
})
138153
}
139154

140155
pub fn text(&self) -> Result<String> {
141-
Ok(self.text.Text()?.to_string_lossy())
156+
Ok(self.inner.text.Text()?.to_string_lossy())
142157
}
143158

144159
pub fn set_text(&mut self, s: impl AsRef<str>) -> Result<()> {
145-
self.text.SetText(&HSTRING::from(s.as_ref()))?;
160+
self.inner.text.SetText(&HSTRING::from(s.as_ref()))?;
146161
Ok(())
147162
}
148163

149164
pub fn size(&self) -> Result<Size> {
150-
Ok(Size::new(
151-
self.parent.Width()?,
152-
(self.parent.Height()? - 40.0).max(0.0),
153-
))
165+
if let Some(parent) = self.inner.parent.borrow().as_ref() {
166+
Ok(Size::new(
167+
parent.Width()?,
168+
(parent.Height()? - 40.0).max(0.0),
169+
))
170+
} else {
171+
Ok(Size::zero())
172+
}
154173
}
155174
}
156175

157176
impl AsContainer for TabViewItem {
158177
fn as_container(&self) -> BorrowedContainer<'_> {
159-
BorrowedContainer::winui(&self.canvas)
178+
BorrowedContainer::winui(&self.inner.canvas)
160179
}
161180
}

winio/examples/subviews/dummy.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ pub enum DummyPageMessage {
2020
impl Component for DummyPage {
2121
type Error = Error;
2222
type Event = DummyPageEvent;
23-
type Init<'a> = (&'a TabView, &'static str, &'static str);
23+
type Init<'a> = (&'static str, &'static str);
2424
type Message = DummyPageMessage;
2525

2626
async fn init(
27-
(tabview, name, feature): Self::Init<'_>,
27+
(name, feature): Self::Init<'_>,
2828
_sender: &ComponentSender<Self>,
2929
) -> Result<Self> {
3030
init! {
31-
window: TabViewItem = (tabview) => {
31+
window: TabViewItem = (()) => {
3232
text: name,
3333
},
3434
label: Label = (&window) => {

winio/examples/subviews/fs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ pub enum FsPageMessage {
4040
impl Component for FsPage {
4141
type Error = Error;
4242
type Event = FsPageEvent;
43-
type Init<'a> = &'a TabView;
43+
type Init<'a> = ();
4444
type Message = FsPageMessage;
4545

46-
async fn init(tabview: Self::Init<'_>, sender: &ComponentSender<Self>) -> Result<Self> {
46+
async fn init(_init: Self::Init<'_>, sender: &ComponentSender<Self>) -> Result<Self> {
4747
let path = "Cargo.toml";
4848
init! {
49-
window: TabViewItem = (tabview) => {
49+
window: TabViewItem = (()) => {
5050
text: "File IO",
5151
},
5252
canvas: Canvas = (&window),

winio/examples/subviews/gallery.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ pub enum GalleryPageMessage {
8383
impl Component for GalleryPage {
8484
type Error = Error;
8585
type Event = GalleryPageEvent;
86-
type Init<'a> = &'a TabView;
86+
type Init<'a> = ();
8787
type Message = GalleryPageMessage;
8888

89-
async fn init(tabview: Self::Init<'_>, sender: &ComponentSender<Self>) -> Result<Self> {
89+
async fn init(_init: Self::Init<'_>, sender: &ComponentSender<Self>) -> Result<Self> {
9090
let path = dirs::picture_dir();
9191
init! {
92-
window: TabViewItem = (tabview) => {
92+
window: TabViewItem = (()) => {
9393
text: "Images",
9494
},
9595
canvas: Canvas = (&window),

winio/examples/subviews/markdown.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ pub enum MarkdownPageMessage {
4949
impl Component for MarkdownPage {
5050
type Error = Error;
5151
type Event = MarkdownPageEvent;
52-
type Init<'a> = &'a TabView;
52+
type Init<'a> = ();
5353
type Message = MarkdownPageMessage;
5454

55-
async fn init(tabview: Self::Init<'_>, sender: &ComponentSender<Self>) -> Result<Self> {
55+
async fn init(_init: Self::Init<'_>, sender: &ComponentSender<Self>) -> Result<Self> {
5656
let path = "README.md";
5757
init! {
58-
window: TabViewItem = (tabview) => {
58+
window: TabViewItem = (()) => {
5959
text: "Markdown",
6060
},
6161
webview: FailableWebView = (&window),

winio/examples/subviews/media.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ pub enum MediaPageMessage {
4747
impl Component for MediaPage {
4848
type Error = Error;
4949
type Event = MediaPageEvent;
50-
type Init<'a> = &'a TabView;
50+
type Init<'a> = ();
5151
type Message = MediaPageMessage;
5252

53-
async fn init(tabview: Self::Init<'_>, sender: &ComponentSender<Self>) -> Result<Self> {
53+
async fn init(_init: Self::Init<'_>, sender: &ComponentSender<Self>) -> Result<Self> {
5454
init! {
55-
window: TabViewItem = (tabview) => {
55+
window: TabViewItem = (()) => {
5656
text: "Media",
5757
},
5858
media: Media = (&window),

0 commit comments

Comments
 (0)