Skip to content

Commit

Permalink
LSP preview: fix some issue related to geometry
Browse files Browse the repository at this point in the history
 - make sure that the initial size is proper by calling show() on the preview ui
   after the factory has been set
 - ensure that there is no recursion if the inner layout info depends on the size
   (Fixes #3989)
 - Ensure that the geometry constraints are respected when previewing a component
   that was already resized
  • Loading branch information
ogoffart committed Jan 2, 2024
1 parent 617d092 commit ba738be
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 87 deletions.
6 changes: 1 addition & 5 deletions tools/lsp/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,11 +495,7 @@ pub fn send_status_notification(sender: &crate::ServerNotifier, message: &str, h
.unwrap_or_else(|e| eprintln!("Error sending notification: {:?}", e));
}

pub fn reset_selections(ui: Option<&ui::PreviewUi>) {
let Some(ui) = ui else {
return;
};

pub fn reset_selections(ui: &ui::PreviewUi) {
let model = Rc::new(slint::VecModel::from(Vec::new()));
ui.set_selections(slint::ModelRc::from(model));
}
Expand Down
8 changes: 5 additions & 3 deletions tools/lsp/preview/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ fn open_ui_impl(preview_state: &mut PreviewState) {

slint::CloseRequestResponse::HideWindow
});
ui.show().unwrap();
}

pub fn close_ui() {
Expand Down Expand Up @@ -352,14 +351,17 @@ pub fn update_preview_area(compiled: ComponentDefinition) {

let shared_handle = preview_state.handle.clone();

let ui = preview_state.ui.as_ref().unwrap();
super::set_preview_factory(
preview_state.ui.as_ref().unwrap(),
ui,
compiled,
Box::new(move |instance| {
shared_handle.replace(Some(instance));
}),
);
super::reset_selections(preview_state.ui.as_ref());
super::reset_selections(ui);

ui.show().unwrap();
});
}

Expand Down
5 changes: 3 additions & 2 deletions tools/lsp/preview/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,14 +353,15 @@ pub fn update_preview_area(compiled: slint_interpreter::ComponentDefinition) {

let shared_handle = preview_state.handle.clone();

let ui = preview_state.ui.as_ref().unwrap();
super::set_preview_factory(
preview_state.ui.as_ref().unwrap(),
ui,
compiled,
Box::new(move |instance| {
shared_handle.replace(Some(instance));
}),
);
super::reset_selections(preview_state.ui.as_ref());
super::reset_selections(ui);
})
}

Expand Down
172 changes: 95 additions & 77 deletions tools/lsp/ui/main.slint
Original file line number Diff line number Diff line change
Expand Up @@ -38,113 +38,131 @@ export component PreviewUi inherits Window {
title: "Slint Live-Preview";
icon: @image-url("assets/slint-logo-small-light.png");

if (!show-preview-ui): VerticalLayout {
no-ui-drawing-rect := Rectangle {
ComponentContainer {
component-factory <=> root.preview-area;
width: clamp(no-ui-drawing-rect.width, self.min-width, self.max-width);
height: clamp(no-ui-drawing-rect.height, self.min-height, self.max-height);
VerticalLayout {
if (!show-preview-ui): no-ui-drawing-rect := Rectangle {
VerticalLayout {
ComponentContainer {
component-factory <=> root.preview-area;
}
}

// Diagnostics overlay:
DiagnosticsOverlay {
width: 100%;
height: 100%;
diagnostics <=> root.diagnostics;
show-document(url, line, column) => { root.show-document(url, line, column); }
}
}
}
if (show-preview-ui): VerticalLayout {
HeaderBar {
vertical-stretch: 0.0;
if (show-preview-ui): VerticalLayout {
HeaderBar {
vertical-stretch: 0.0;

height: self.preferred-height;
height: self.preferred-height;

i-pick-button := Button {
text: "Pick Mode";
checkable: true;
checked <=> root.design-mode;
}
i-pick-button := Button {
text: "Pick Mode";
checkable: true;
checked <=> root.design-mode;
}

Text {
text: "Style:";
vertical-alignment: center;
}
i-style-select := ComboBox {
model: root.known-styles;
current-value <=> current-style;
selected(value) => {
root.style-changed();
Text {
text: "Style:";
vertical-alignment: center;
}
i-style-select := ComboBox {
model: root.known-styles;
current-value <=> current-style;
selected(value) => {
root.style-changed();
}
}
}

Text {
text: root.status-text;
vertical-alignment: center;
Text {
text: root.status-text;
vertical-alignment: center;
}
}
}

i-scroll-view := ScrollView {
property <length> border: 60px;
i-scroll-view := ScrollView {
preferred-height: max(i-preview-area-container.preferred-height, i-preview-area-container.min-height) + 2 * i-scroll-view.border;
preferred-width: max(i-preview-area-container.preferred-width, i-preview-area-container.min-width) + 2 * i-scroll-view.border;

viewport-width: i-drawing-rect.width;
viewport-height: i-drawing-rect.height;

i-drawing-rect := Rectangle {
background: Colors.white;
property <length> border: 60px;

width: max(i-scroll-view.visible-width, i-resizer.width + i-scroll-view.border);
height: max(i-scroll-view.visible-height, i-resizer.height + i-scroll-view.border);
viewport-width: i-drawing-rect.width;
viewport-height: i-drawing-rect.height;

i-resizer := Resizer {
is-resizable <=> i-preview-area-container.is-resizable;
i-drawing-rect := Rectangle {
background: Colors.white;

resize(w, h) => {
i-preview-area-container.width = clamp(w, i-preview-area-container.min-width, i-preview-area-container.max-width);
i-preview-area-container.height = clamp(h, i-preview-area-container.min-height, i-preview-area-container.max-height);
}
width: max(i-scroll-view.visible-width, i-resizer.width + i-scroll-view.border);
height: max(i-scroll-view.visible-height, i-resizer.height + i-scroll-view.border);

width <=> i-preview-area-container.width;
height <=> i-preview-area-container.height;

i-preview-area-container := ComponentContainer {
property <bool> is-resizable: (self.min-width != self.max-width && self.min-height != self.max-height) && self.has-component;

component-factory <=> root.preview-area;
}
i-resizer := Resizer {
is-resizable <=> i-preview-area-container.is-resizable;

i-selection-area := TouchArea {
clicked => { root.select-at(self.pressed-x, self.pressed-y); }
double-clicked => { root.select-into(self.pressed-x, self.pressed-y); }
mouse-cursor: crosshair;
enabled <=> root.design-mode;
resize(w, h) => {
i-preview-area-container.width = clamp(w, i-preview-area-container.min-width, i-preview-area-container.max-width);
i-preview-area-container.height = clamp(h, i-preview-area-container.min-height, i-preview-area-container.max-height);
}

x: i-preview-area-container.x;
y: i-preview-area-container.y;
width: i-preview-area-container.width;
height: i-preview-area-container.height;
}

i-selection-display-area := Rectangle {
x: i-preview-area-container.x;
y: i-preview-area-container.y;
width: i-preview-area-container.width;
height: i-preview-area-container.height;
i-preview-area-container := ComponentContainer {

property <bool> is-resizable: (self.min-width != self.max-width && self.min-height != self.max-height) && self.has-component;

component-factory <=> root.preview-area;

// The width and the height can't depend on the layout info of the inner item otherwise this would
// cause a recursion if this happens (#3989)
// Instead, we use a init function to initialize
width: 0px;
height: 0px;
init => {
self.width = max(self.preferred-width, self.min-width);
self.height = max(self.preferred-height, self.min-height);
}
}

// Also make a condition that abuses the fact that the init callback
// is called everytime the condition is dirty, to make sure that the size
// is within the bounds.
// Querty the preview-area to make sure this is evaluated when it changes
if i-preview-area-container.has-component && root.preview-area == i-preview-area-container.component-factory : Rectangle {
init => {
i-preview-area-container.width = clamp(i-preview-area-container.width, i-preview-area-container.min-width, i-preview-area-container.max-width);
i-preview-area-container.height = clamp(i-preview-area-container.height, i-preview-area-container.min-height, i-preview-area-container.max-height);
}
}

for s in root.selections: Rectangle {
x: s.x;
y: s.y;
width: s.width;
height: s.height;
border-color: s.border-color;
border-width: 1px;
i-selection-area := TouchArea {
clicked => { root.select-at(self.pressed-x, self.pressed-y); }
double-clicked => { root.select-into(self.pressed-x, self.pressed-y); }
mouse-cursor: crosshair;
enabled <=> root.design-mode;
}

i-selection-display-area := Rectangle {
for s in root.selections: Rectangle {
x: s.x;
y: s.y;
width: s.width;
height: s.height;
border-color: s.border-color;
border-width: 1px;
}
}
}
}

// Diagnostics overlay:
DiagnosticsOverlay {
diagnostics <=> root.diagnostics;
show-document(url, line, column) => { root.show-document(url, line, column); }
// Diagnostics overlay:
DiagnosticsOverlay {
diagnostics <=> root.diagnostics;
show-document(url, line, column) => { root.show-document(url, line, column); }
}
}
}
}
Expand Down

0 comments on commit ba738be

Please sign in to comment.