mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 06:41:14 +00:00
Implement ScrollBarPolicy property for ScrollView (#6442)
ChangeLog: ScrollView: added vertical-bar-policy and horizontal-bar-policy Fixes: #3552 Fixes: #5578
This commit is contained in:
parent
3784780e22
commit
1e4de3fe0c
11 changed files with 125 additions and 42 deletions
|
@ -17,6 +17,7 @@ using for loops may be added in the future and is tracked in issue #407.
|
|||
- **`viewport-width`** and **`viewport-height`** (_in-out_ _length_): The `width` and `length` properties of the viewport
|
||||
- **`viewport-x`** and **`viewport-y`** (_in-out_ _length_): The `x` and `y` properties of the viewport. Usually these are negative
|
||||
- **`visible-width`** and **`visible-height`** (_out_ _length_): The size of the visible area of the ScrollView (not including the scrollbar)
|
||||
- **`vertical-bar-policy`** and **`horizontal-bar-policy`** (_in_ _ScrollBarPolicy_): The vertical and horizontal scroll bar visibility policy. The default value is `ScrollBarPolicy.as-needed`.
|
||||
|
||||
### Callbacks
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { HorizontalBox, VerticalBox, ListView, StandardListView, GroupBox } from "std-widgets.slint";
|
||||
import { HorizontalBox, VerticalBox, ListView, StandardListView, GroupBox, ComboBox } from "std-widgets.slint";
|
||||
import { GallerySettings } from "../gallery_settings.slint";
|
||||
import { Page } from "page.slint";
|
||||
|
||||
|
@ -10,12 +10,51 @@ export component ListViewPage inherits Page {
|
|||
show-enable-switch: false;
|
||||
description: @tr("ListViews can be used to display a list of elements. The StandardListBox is like the default ListView just with a default text based definition of the visual items. Both can be imported from \"std-widgets.slint\"");
|
||||
|
||||
GroupBox {
|
||||
title: @tr("Scroll Bar Policy:");
|
||||
function policy-from-index(index: int) -> ScrollBarPolicy
|
||||
{
|
||||
if (index == 1) {
|
||||
return ScrollBarPolicy.always-on;
|
||||
}
|
||||
if (index == 2) {
|
||||
return ScrollBarPolicy.always-off;
|
||||
}
|
||||
return ScrollBarPolicy.as-needed;
|
||||
}
|
||||
|
||||
HorizontalBox {
|
||||
HorizontalBox {
|
||||
Text {
|
||||
text: @tr("Vertical:");
|
||||
}
|
||||
vertical-bar-policy := ComboBox {
|
||||
in-out property<ScrollBarPolicy> current-policy: policy-from-index(self.current-index);
|
||||
|
||||
model: [@tr("As Needed"), @tr("Always On"), @tr("Always Off")];
|
||||
}
|
||||
}
|
||||
HorizontalBox {
|
||||
Text {
|
||||
text: @tr("Horizontal:");
|
||||
}
|
||||
horizontal-bar-policy := ComboBox {
|
||||
in-out property<ScrollBarPolicy> current-policy: policy-from-index(self.current-index);
|
||||
|
||||
model: [@tr("As Needed"), @tr("Always On"), @tr("Always Off")];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalBox {
|
||||
vertical-stretch: 1;
|
||||
GroupBox {
|
||||
title: @tr("ListView");
|
||||
|
||||
ListView {
|
||||
vertical-bar-policy: vertical-bar-policy.current-policy;
|
||||
horizontal-bar-policy: horizontal-bar-policy.current-policy;
|
||||
vertical-stretch: 0;
|
||||
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] : HorizontalBox {
|
||||
Image {
|
||||
|
@ -34,6 +73,8 @@ export component ListViewPage inherits Page {
|
|||
vertical-stretch: 0;
|
||||
|
||||
StandardListView {
|
||||
vertical-bar-policy: vertical-bar-policy.current-policy;
|
||||
horizontal-bar-policy: horizontal-bar-policy.current-policy;
|
||||
model: [
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
{text: @tr("Lorem")}, {text: @tr("ipsum")},{text: @tr("dolor")},{text: @tr("sit")},{text: @tr("amet")},{text: @tr("consetetur")},
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
use i_slint_core::input::FocusEventResult;
|
||||
use i_slint_core::items::ScrollBarPolicy;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -22,6 +23,8 @@ pub struct NativeScrollView {
|
|||
pub native_padding_bottom: Property<LogicalLength>,
|
||||
pub enabled: Property<bool>,
|
||||
pub has_focus: Property<bool>,
|
||||
pub vertical_bar_policy: Property<ScrollBarPolicy>,
|
||||
pub horizontal_bar_policy: Property<ScrollBarPolicy>,
|
||||
data: Property<NativeSliderData>,
|
||||
widget_ptr: std::cell::Cell<SlintTypeErasedWidgetPtr>,
|
||||
animation_tracker: Property<i32>,
|
||||
|
@ -292,6 +295,9 @@ impl Item for NativeScrollView {
|
|||
};
|
||||
let enabled: bool = this.enabled();
|
||||
let has_focus: bool = this.has_focus();
|
||||
let vertical_bar_visible = (this.vertical_bar_policy() == ScrollBarPolicy::AlwaysOn) || ((this.vertical_bar_policy() == ScrollBarPolicy::AsNeeded) && (this.vertical_max().get() > 0.0));
|
||||
let horizontal_bar_visible = (this.horizontal_bar_policy() == ScrollBarPolicy::AlwaysOn) || ((this.horizontal_bar_policy() == ScrollBarPolicy::AsNeeded) && (this.horizontal_max().get() > 0.0));
|
||||
let scrollbar_bar_visible = vertical_bar_visible || horizontal_bar_visible;
|
||||
let frame_around_contents = cpp!(unsafe [
|
||||
painter as "QPainterPtr*",
|
||||
widget as "QWidget*",
|
||||
|
@ -300,7 +306,8 @@ impl Item for NativeScrollView {
|
|||
margins as "QMargins",
|
||||
enabled as "bool",
|
||||
has_focus as "bool",
|
||||
initial_state as "int"
|
||||
initial_state as "int",
|
||||
scrollbar_bar_visible as "bool"
|
||||
] -> bool as "bool" {
|
||||
ensure_initialized();
|
||||
QStyleOptionFrame frameOption;
|
||||
|
@ -327,11 +334,15 @@ impl Item for NativeScrollView {
|
|||
frameOption.rect = QRect(QPoint(), (size / dpr) - corner_size);
|
||||
qApp->style()->drawControl(QStyle::CE_ShapedFrame, &frameOption, painter->get(), widget);
|
||||
frameOption.rect = QRect(frameOption.rect.bottomRight() + QPoint(1, 1), corner_size);
|
||||
qApp->style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &frameOption, painter->get(), widget);
|
||||
if (scrollbar_bar_visible) {
|
||||
qApp->style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &frameOption, painter->get(), widget);
|
||||
}
|
||||
} else {
|
||||
qApp->style()->drawControl(QStyle::CE_ShapedFrame, &frameOption, painter->get(), widget);
|
||||
frameOption.rect = QRect(frameOption.rect.bottomRight() + QPoint(1, 1) - QPoint(margins.right(), margins.bottom()), corner_size);
|
||||
qApp->style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &frameOption, painter->get(), widget);
|
||||
if (scrollbar_bar_visible) {
|
||||
qApp->style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, &frameOption, painter->get(), widget);
|
||||
}
|
||||
}
|
||||
return foac;
|
||||
});
|
||||
|
@ -399,36 +410,40 @@ impl Item for NativeScrollView {
|
|||
|
||||
let scrollbars_width = (margins.right - margins.left) as f32;
|
||||
let scrollbars_height = (margins.bottom - margins.top) as f32;
|
||||
draw_scrollbar(
|
||||
false,
|
||||
qttypes::QRectF {
|
||||
x: ((size.width as f32 / dpr) - if frame_around_contents { scrollbars_width } else { margins.right as _ }) as _,
|
||||
y: (if frame_around_contents { 0 } else { margins.top }) as _,
|
||||
width: scrollbars_width as _,
|
||||
height: ((size.height as f32 / dpr) - if frame_around_contents { scrollbars_height } else { (margins.bottom + margins.top) as f32 }) as _,
|
||||
},
|
||||
this.vertical_value().get() as i32,
|
||||
this.vertical_page_size().get() as i32,
|
||||
this.vertical_max().get() as i32,
|
||||
data.active_controls,
|
||||
data.pressed == 2,
|
||||
initial_state
|
||||
);
|
||||
draw_scrollbar(
|
||||
true,
|
||||
qttypes::QRectF {
|
||||
x: (if frame_around_contents { 0 } else { margins.left }) as _,
|
||||
y: ((size.height as f32 / dpr) - if frame_around_contents { scrollbars_height } else { margins.bottom as _ }) as _,
|
||||
width: ((size.width as f32 / dpr) - if frame_around_contents { scrollbars_width } else { (margins.left + margins.right) as _ }) as _,
|
||||
height: (scrollbars_height) as _,
|
||||
},
|
||||
this.horizontal_value().get() as i32,
|
||||
this.horizontal_page_size().get() as i32,
|
||||
this.horizontal_max().get() as i32,
|
||||
data.active_controls,
|
||||
data.pressed == 1,
|
||||
initial_state
|
||||
);
|
||||
if vertical_bar_visible {
|
||||
draw_scrollbar(
|
||||
false,
|
||||
qttypes::QRectF {
|
||||
x: ((size.width as f32 / dpr) - if frame_around_contents { scrollbars_width } else { margins.right as _ }) as _,
|
||||
y: (if frame_around_contents { 0 } else { margins.top }) as _,
|
||||
width: scrollbars_width as _,
|
||||
height: ((size.height as f32 / dpr) - if frame_around_contents { scrollbars_height } else { (margins.bottom + margins.top) as f32 }) as _,
|
||||
},
|
||||
this.vertical_value().get() as i32,
|
||||
this.vertical_page_size().get() as i32,
|
||||
this.vertical_max().get() as i32,
|
||||
data.active_controls,
|
||||
data.pressed == 2,
|
||||
initial_state
|
||||
);
|
||||
}
|
||||
if horizontal_bar_visible {
|
||||
draw_scrollbar(
|
||||
true,
|
||||
qttypes::QRectF {
|
||||
x: (if frame_around_contents { 0 } else { margins.left }) as _,
|
||||
y: ((size.height as f32 / dpr) - if frame_around_contents { scrollbars_height } else { margins.bottom as _ }) as _,
|
||||
width: ((size.width as f32 / dpr) - if frame_around_contents { scrollbars_width } else { (margins.left + margins.right) as _ }) as _,
|
||||
height: (scrollbars_height) as _,
|
||||
},
|
||||
this.horizontal_value().get() as i32,
|
||||
this.horizontal_page_size().get() as i32,
|
||||
this.horizontal_max().get() as i32,
|
||||
data.active_controls,
|
||||
data.pressed == 1,
|
||||
initial_state
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -421,6 +421,16 @@ macro_rules! for_each_enums {
|
|||
/// The ["alternate reverse" direction as defined in CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-direction#alternate-reverse).
|
||||
AlternateReverse,
|
||||
}
|
||||
|
||||
/// This enum describes the scrollbar visibility
|
||||
enum ScrollBarPolicy {
|
||||
/// Scrolbar will be visible only when needed
|
||||
AsNeeded,
|
||||
/// Scrollbar never shown
|
||||
AlwaysOff,
|
||||
/// Scrollbar always visible
|
||||
AlwaysOn,
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -536,6 +536,8 @@ export component NativeScrollView {
|
|||
out property <length> native-padding-top;
|
||||
out property <length> native-padding-bottom;
|
||||
in property <bool> has_focus;
|
||||
in property <ScrollBarPolicy> vertical-bar-policy;
|
||||
in property <ScrollBarPolicy> horizontal-bar-policy;
|
||||
in property <bool> enabled: true;
|
||||
//-default_size_binding:expands_to_parent_geometry
|
||||
//-is_internal
|
||||
|
|
|
@ -11,12 +11,14 @@ export component ScrollBar {
|
|||
in-out property <length> maximum;
|
||||
in-out property <length> page-size;
|
||||
in-out property <length> value;
|
||||
in property <ScrollBarPolicy> policy: ScrollBarPolicy.as-needed;
|
||||
|
||||
private property <length> track-size: root.horizontal ? root.width - 2 * root.offset : root.height - 2 * offset;
|
||||
private property <length> step-size: 10px;
|
||||
private property <length> offset: 2px;
|
||||
|
||||
opacity: 0.7;
|
||||
visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0);
|
||||
|
||||
Rectangle {
|
||||
border-radius: thumb.border-radius;
|
||||
|
@ -84,6 +86,8 @@ export component ScrollView {
|
|||
in-out property <length> viewport-height <=> flickable.viewport-height;
|
||||
in-out property <length> viewport-x <=> flickable.viewport-x;
|
||||
in-out property <length> viewport-y <=> flickable.viewport-y;
|
||||
in property <ScrollBarPolicy> vertical-bar-policy <=> vertical-bar.policy;
|
||||
in property <ScrollBarPolicy> horizontal-bar-policy <=> horizontal-bar.policy;
|
||||
// FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus
|
||||
in-out property <bool> has-focus;
|
||||
|
||||
|
@ -115,7 +119,6 @@ export component ScrollView {
|
|||
horizontal: false;
|
||||
maximum: flickable.viewport-height - flickable.height;
|
||||
page-size: flickable.height;
|
||||
visible: flickable.viewport-height > flickable.height;
|
||||
}
|
||||
|
||||
horizontal-bar := ScrollBar {
|
||||
|
@ -127,6 +130,5 @@ export component ScrollView {
|
|||
horizontal: true;
|
||||
maximum: flickable.viewport-width - flickable.width;
|
||||
page-size: flickable.width;
|
||||
visible: flickable.viewport-width > flickable.width;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ export component ScrollBar inherits Rectangle {
|
|||
in-out property <length> maximum;
|
||||
in-out property <length> page-size;
|
||||
in-out property <length> value;
|
||||
in property <ScrollBarPolicy> policy: ScrollBarPolicy.as-needed;
|
||||
|
||||
private property <length> track-size: root.horizontal ? root.width - 2 * root.offset : root.height - 2 * offset;
|
||||
private property <length> step-size: 10px;
|
||||
|
@ -17,6 +18,7 @@ export component ScrollBar inherits Rectangle {
|
|||
private property <length> pad: 2px;
|
||||
|
||||
background: transparent;
|
||||
visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0);
|
||||
|
||||
states [
|
||||
hover when touch-area.has-hover : {
|
||||
|
@ -92,6 +94,8 @@ export component ScrollView {
|
|||
in-out property <length> viewport-height <=> flickable.viewport-height;
|
||||
in-out property <length> viewport-x <=> flickable.viewport-x;
|
||||
in-out property <length> viewport-y <=> flickable.viewport-y;
|
||||
in property <ScrollBarPolicy> vertical-bar-policy <=> vertical-bar.policy;
|
||||
in property <ScrollBarPolicy> horizontal-bar-policy <=> horizontal-bar.policy;
|
||||
// FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus
|
||||
in-out property <bool> has-focus;
|
||||
|
||||
|
@ -125,7 +129,6 @@ export component ScrollView {
|
|||
horizontal: false;
|
||||
maximum: flickable.viewport-height - flickable.height;
|
||||
page-size: flickable.height;
|
||||
visible: flickable.viewport-height > flickable.height;
|
||||
}
|
||||
|
||||
horizontal-bar := ScrollBar {
|
||||
|
@ -137,6 +140,5 @@ export component ScrollView {
|
|||
horizontal: true;
|
||||
maximum: flickable.viewport-width - flickable.width;
|
||||
page-size: flickable.width;
|
||||
visible: flickable.viewport-width > flickable.width;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ component ScrollBar inherits Rectangle {
|
|||
in-out property <length> maximum;
|
||||
in-out property <length> page-size;
|
||||
in-out property <length> value;
|
||||
in property <ScrollBarPolicy> policy: ScrollBarPolicy.as-needed;
|
||||
in property <bool> enabled;
|
||||
|
||||
private property <length> offset: 16px;
|
||||
|
@ -46,6 +47,7 @@ component ScrollBar inherits Rectangle {
|
|||
|
||||
border-width: 1px;
|
||||
border-radius: 7px;
|
||||
visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0);
|
||||
|
||||
states [
|
||||
hover when touch-area.has-hover || down-scroll-button.has-hover || up-scroll-button.has-hover : {
|
||||
|
@ -133,6 +135,9 @@ export component ScrollView {
|
|||
in-out property <length> viewport-height <=> flickable.viewport-height;
|
||||
in-out property <length> viewport-x <=> flickable.viewport-x;
|
||||
in-out property <length> viewport-y <=> flickable.viewport-y;
|
||||
in property <ScrollBarPolicy> vertical-bar-policy <=> vertical-bar.policy;
|
||||
in property <ScrollBarPolicy> horizontal-bar-policy <=> horizontal-bar.policy;
|
||||
|
||||
// FIXME: remove. This property is currently set by the ListView and is used by the native style to draw the scrollbar differently when it has focus
|
||||
in-out property <bool> has-focus;
|
||||
|
||||
|
@ -164,7 +169,6 @@ export component ScrollView {
|
|||
horizontal: false;
|
||||
maximum: flickable.viewport-height - flickable.height;
|
||||
page-size: flickable.height;
|
||||
visible: flickable.viewport-height > flickable.height;
|
||||
}
|
||||
|
||||
horizontal-bar := ScrollBar {
|
||||
|
@ -176,6 +180,5 @@ export component ScrollView {
|
|||
horizontal: true;
|
||||
maximum: flickable.viewport-width - flickable.width;
|
||||
page-size: flickable.width;
|
||||
visible: flickable.viewport-width > flickable.width;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ component ScrollBar inherits Rectangle {
|
|||
// this is always negative and bigger than -maximum
|
||||
in-out property <length> value;
|
||||
in-out property <bool> enabled <=> touch-area.enabled;
|
||||
in property <ScrollBarPolicy> policy: ScrollBarPolicy.as-needed;
|
||||
|
||||
states [
|
||||
disabled when !touch-area.enabled : {
|
||||
|
@ -25,6 +26,8 @@ component ScrollBar inherits Rectangle {
|
|||
}
|
||||
]
|
||||
|
||||
visible: (self.policy == ScrollBarPolicy.always-on) || (self.policy == ScrollBarPolicy.as-needed && self.maximum > 0);
|
||||
|
||||
state-layer := Rectangle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -95,6 +98,8 @@ export component ScrollView {
|
|||
in-out property <length> viewport-height <=> flickable.viewport-height;
|
||||
in-out property <length> viewport-x <=> flickable.viewport-x;
|
||||
in-out property <length> viewport-y <=> flickable.viewport-y;
|
||||
in property <ScrollBarPolicy> vertical-bar-policy <=> vertical-bar.policy;
|
||||
in property <ScrollBarPolicy> horizontal-bar-policy <=> horizontal-bar.policy;
|
||||
|
||||
callback scrolled <=> flickable.flicked;
|
||||
|
||||
|
@ -125,7 +130,6 @@ export component ScrollView {
|
|||
maximum: flickable.viewport-height - flickable.height;
|
||||
page-size: flickable.height;
|
||||
enabled: root.enabled;
|
||||
visible: flickable.viewport-height > flickable.height;
|
||||
}
|
||||
|
||||
horizontal-bar := ScrollBar {
|
||||
|
@ -137,6 +141,5 @@ export component ScrollView {
|
|||
maximum: flickable.viewport-width - flickable.width;
|
||||
page-size: flickable.width;
|
||||
enabled: root.enabled;
|
||||
visible: flickable.viewport-width > flickable.width;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ export component InternalScrollView {
|
|||
out property <length> visible-height <=> fli.height;
|
||||
in-out property <bool> has-focus <=> native.has-focus;
|
||||
in property <bool> enabled <=> native.enabled;
|
||||
in property <ScrollBarPolicy> vertical-bar-policy <=> native.vertical-bar-policy;
|
||||
in property <ScrollBarPolicy> horizontal-bar-policy <=> native.horizontal-bar-policy;
|
||||
|
||||
// Used by the StandardTableView
|
||||
out property <length> native-padding-left: native.native-padding-left;
|
||||
|
|
|
@ -12,6 +12,8 @@ export component ScrollView {
|
|||
in-out property <length> viewport-height <=> internal.viewport-height;
|
||||
in-out property <length> viewport-x <=> internal.viewport-x;
|
||||
in-out property <length> viewport-y <=> internal.viewport-y;
|
||||
in property <ScrollBarPolicy> vertical-bar-policy <=> internal.vertical-bar-policy;
|
||||
in property <ScrollBarPolicy> horizontal-bar-policy <=> internal.horizontal-bar-policy;
|
||||
|
||||
callback scrolled <=> internal.scrolled;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue