Pane Grid `PickList` does not work when `Responsive` is present in Pane's controls
MichalLebeda opened this issue · comments
MichalLebeda commented
Is there an existing issue for this?
- I have searched the existing issues.
Is this issue related to iced?
- My hardware is compatible and my graphics drivers are up-to-date.
What happened?
When adding Responsive
to the pane's TitleBar
controls, PickList
inside Content
does not open when clicked. PickList
outside the PaneGrid
works ok. I suppose that the PaneGrid
/Content
takes only single Overlay
into an account. During my investigation I found out that the overlay
function is not called for children of Content
but I'm not 100% sure as my knowledge of the code base is limited.
use std::fmt::Display;
use iced::{
Application, Color, Command, Element, Length, Settings, Size, Subscription,
};
use iced::alignment::{self, Alignment, Horizontal, Vertical};
use iced::executor;
use iced::keyboard;
use iced::theme::{self, Theme};
use iced::widget::{button, column, container, pick_list, responsive, row, scrollable, text};
use iced::widget::pane_grid::{self, PaneGrid};
pub fn main() -> iced::Result {
Example::run(Settings::default())
}
struct Example {
panes: pane_grid::State<Pane>,
panes_created: usize,
focus: Option<pane_grid::Pane>,
}
#[derive(Debug, Clone, Copy)]
enum Message {
AnimalPicked(Animal, Option<pane_grid::Pane>),
Split(pane_grid::Axis, pane_grid::Pane),
SplitFocused(pane_grid::Axis),
FocusAdjacent(pane_grid::Direction),
Clicked(pane_grid::Pane),
Dragged(pane_grid::DragEvent),
Resized(pane_grid::ResizeEvent),
TogglePin(pane_grid::Pane),
Maximize(pane_grid::Pane),
Restore,
Close(pane_grid::Pane),
CloseFocused,
}
impl Application for Example {
type Message = Message;
type Theme = Theme;
type Executor = executor::Default;
type Flags = ();
fn new(_flags: ()) -> (Self, Command<Message>) {
let (panes, _) = pane_grid::State::new(Pane::new(0));
(
Example {
panes,
panes_created: 1,
focus: None,
},
Command::none(),
)
}
fn title(&self) -> String {
String::from("Pane grid - Iced")
}
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::Split(axis, pane) => {
let result =
self.panes.split(axis, pane, Pane::new(self.panes_created));
if let Some((pane, _)) = result {
self.focus = Some(pane);
}
self.panes_created += 1;
}
Message::SplitFocused(axis) => {
if let Some(pane) = self.focus {
let result = self.panes.split(
axis,
pane,
Pane::new(self.panes_created),
);
if let Some((pane, _)) = result {
self.focus = Some(pane);
}
self.panes_created += 1;
}
}
Message::FocusAdjacent(direction) => {
if let Some(pane) = self.focus {
if let Some(adjacent) = self.panes.adjacent(pane, direction)
{
self.focus = Some(adjacent);
}
}
}
Message::Clicked(pane) => {
self.focus = Some(pane);
}
Message::Resized(pane_grid::ResizeEvent { split, ratio }) => {
self.panes.resize(split, ratio);
}
Message::Dragged(pane_grid::DragEvent::Dropped {
pane,
target,
}) => {
self.panes.drop(pane, target);
}
Message::Dragged(_) => {}
Message::TogglePin(pane) => {
if let Some(Pane { is_pinned, .. }) = self.panes.get_mut(pane) {
*is_pinned = !*is_pinned;
}
}
Message::Maximize(pane) => self.panes.maximize(pane),
Message::Restore => {
self.panes.restore();
}
Message::Close(pane) => {
if let Some((_, sibling)) = self.panes.close(pane) {
self.focus = Some(sibling);
}
}
Message::CloseFocused => {
if let Some(pane) = self.focus {
if let Some(Pane { is_pinned, .. }) = self.panes.get(pane) {
if !is_pinned {
if let Some((_, sibling)) = self.panes.close(pane) {
self.focus = Some(sibling);
}
}
}
}
}
Message::AnimalPicked(animal, pane) => {
println!("Animal {} picked for pane {:?}", animal, pane)
}
}
Command::none()
}
fn subscription(&self) -> Subscription<Message> {
keyboard::on_key_press(|key_code, modifiers| {
if !modifiers.command() {
return None;
}
handle_hotkey(key_code)
})
}
fn view(&self) -> Element<Message> {
let focus = self.focus;
let total_panes = self.panes.len();
let pane_grid = PaneGrid::new(&self.panes, |id, pane, is_maximized| {
let is_focused = focus == Some(id);
let pin_button = button(
text(if pane.is_pinned { "Unpin" } else { "Pin" }).size(14),
)
.on_press(Message::TogglePin(id))
.padding(3);
let title = row![
pin_button,
"Pane",
text(pane.id.to_string()).style(if is_focused {
PANE_ID_COLOR_FOCUSED
} else {
PANE_ID_COLOR_UNFOCUSED
}),
]
.spacing(5);
let title_bar = pane_grid::TitleBar::new(title)
.controls(view_controls(
id,
total_panes,
pane.is_pinned,
is_maximized,
))
.always_show_controls()
.style(if is_focused {
style::title_bar_focused
} else {
style::title_bar_active
});
pane_grid::Content::new(responsive(move |size| {
view_content(id, total_panes, pane.is_pinned, size)
}))
.title_bar(title_bar)
.style(if is_focused {
style::pane_focused
} else {
style::pane_active
})
})
.width(Length::Fill)
.height(Length::Fill)
.spacing(10)
.on_click(Message::Clicked)
.on_drag(Message::Dragged)
.on_resize(10, Message::Resized);
row(
[
container(pane_grid)
.width(Length::Fill)
.height(Length::Fill)
.padding(10)
.into(),
animal_pick_list(None)
]
).into()
}
}
const PANE_ID_COLOR_UNFOCUSED: Color = Color::from_rgb(
0xFF as f32 / 255.0,
0xC7 as f32 / 255.0,
0xC7 as f32 / 255.0,
);
const PANE_ID_COLOR_FOCUSED: Color = Color::from_rgb(
0xFF as f32 / 255.0,
0x47 as f32 / 255.0,
0x47 as f32 / 255.0,
);
fn handle_hotkey(key: keyboard::Key) -> Option<Message> {
use keyboard::key::{self, Key};
use pane_grid::{Axis, Direction};
match key.as_ref() {
Key::Character("v") => Some(Message::SplitFocused(Axis::Vertical)),
Key::Character("h") => Some(Message::SplitFocused(Axis::Horizontal)),
Key::Character("w") => Some(Message::CloseFocused),
Key::Named(key) => {
let direction = match key {
key::Named::ArrowUp => Some(Direction::Up),
key::Named::ArrowDown => Some(Direction::Down),
key::Named::ArrowLeft => Some(Direction::Left),
key::Named::ArrowRight => Some(Direction::Right),
_ => None,
};
direction.map(Message::FocusAdjacent)
}
_ => None,
}
}
#[derive(Clone, Copy)]
struct Pane {
id: usize,
pub is_pinned: bool,
}
impl Pane {
fn new(id: usize) -> Self {
Self {
id,
is_pinned: false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum Animal {
Cat,
Dog,
}
impl Display for Animal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Animal::Cat => {
write!(f, "cat")
}
Animal::Dog => {
write!(f, "dog")
}
}
}
}
fn animal_pick_list<'a>(pane: Option<pane_grid::Pane>) -> Element<'a, Message> {
pick_list(
[Animal::Dog, Animal::Cat],
Some(Animal::Dog),
move |opt| Message::AnimalPicked(opt, pane),
).into()
}
fn view_content<'a>(
pane: pane_grid::Pane,
total_panes: usize,
is_pinned: bool,
size: Size,
) -> Element<'a, Message> {
let button = |label, message| {
button(
text(label)
.width(Length::Fill)
.horizontal_alignment(alignment::Horizontal::Center)
.size(16),
)
.width(Length::Fill)
.padding(8)
.on_press(message)
};
let animal_pick_list = animal_pick_list(Some(pane));
let controls = column![
button(
"Split horizontally",
Message::Split(pane_grid::Axis::Horizontal, pane),
),
button(
"Split vertically",
Message::Split(pane_grid::Axis::Vertical, pane),
),
animal_pick_list
]
.push_maybe(if total_panes > 1 && !is_pinned {
Some(
button("Close", Message::Close(pane))
.style(theme::Button::Destructive),
)
} else {
None
})
.spacing(5)
.max_width(160);
let content = column![
text(format!("{}x{}", size.width, size.height)).size(24),
controls,
]
.spacing(10)
.align_items(Alignment::Center);
container(scrollable(content))
.width(Length::Fill)
.height(Length::Fill)
.padding(5)
.center_y()
.into()
}
fn view_controls<'a>(
pane: pane_grid::Pane,
total_panes: usize,
is_pinned: bool,
is_maximized: bool,
) -> Element<'a, Message> {
container(
responsive(move |size| {
let mut row = row![].spacing(5)
.width(Length::Fill)
.height(Length::Fill);
let close_btn_text = text("Close")
.height(Length::Fill)
.vertical_alignment(Vertical::Center)
.size(14);
let close = button(close_btn_text)
.style(theme::Button::Destructive)
.height(Length::Fill)
.padding(3)
.on_press_maybe(if total_panes > 1 && !is_pinned {
Some(Message::Close(pane))
} else {
None
});
row = row.push(close).into();
let size_text = text(format!("Responsive size: {:?}", size))
.width(Length::Fill)
.height(Length::Fill)
.vertical_alignment(Vertical::Center)
.horizontal_alignment(Horizontal::Right);
row = row.push(size_text);
row.into()
})
).height(32).width(Length::Fill).into()
}
mod style {
use iced::{Border, Theme};
use iced::widget::container;
pub fn title_bar_active(theme: &Theme) -> container::Appearance {
let palette = theme.extended_palette();
container::Appearance {
text_color: Some(palette.background.strong.text),
background: Some(palette.background.strong.color.into()),
..Default::default()
}
}
pub fn title_bar_focused(theme: &Theme) -> container::Appearance {
let palette = theme.extended_palette();
container::Appearance {
text_color: Some(palette.primary.strong.text),
background: Some(palette.primary.strong.color.into()),
..Default::default()
}
}
pub fn pane_active(theme: &Theme) -> container::Appearance {
let palette = theme.extended_palette();
container::Appearance {
background: Some(palette.background.weak.color.into()),
border: Border {
width: 2.0,
color: palette.background.strong.color,
..Border::default()
},
..Default::default()
}
}
pub fn pane_focused(theme: &Theme) -> container::Appearance {
let palette = theme.extended_palette();
container::Appearance {
background: Some(palette.background.weak.color.into()),
border: Border {
width: 2.0,
color: palette.primary.strong.color,
..Border::default()
},
..Default::default()
}
}
}
What is the expected behavior?
PickList inside pane grid Content opens when clicked
Version
0.12 (thought that using master but had this branch checked out)
Operating System
Linux
Do you have any log output?
No response