edge scroll thickness adjustment (#13445)
Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
@@ -79,6 +79,7 @@ const String kWindowEventOpenMonitorSession = "open_monitor_session";
|
||||
|
||||
const String kOptionViewStyle = "view_style";
|
||||
const String kOptionScrollStyle = "scroll_style";
|
||||
const String kOptionEdgeScrollEdgeThickness = "edge-scroll-edge-thickness";
|
||||
const String kOptionImageQuality = "image_quality";
|
||||
const String kOptionOpenNewConnInTabs = "enable-open-new-connections-in-tabs";
|
||||
const String kOptionTextureRender = "use-texture-render";
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:flutter_hbb/common/widgets/setting_widgets.dart';
|
||||
import 'package:flutter_hbb/consts.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
||||
import 'package:flutter_hbb/desktop/widgets/remote_toolbar.dart';
|
||||
import 'package:flutter_hbb/mobile/widgets/dialog.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:flutter_hbb/models/printer_model.dart';
|
||||
@@ -1738,22 +1739,39 @@ class _DisplayState extends State<_Display> {
|
||||
}
|
||||
|
||||
final groupValue = bind.mainGetUserDefaultOption(key: kOptionScrollStyle);
|
||||
|
||||
onEdgeScrollEdgeThicknessChanged(double value) async {
|
||||
await bind.mainSetUserDefaultOption(
|
||||
key: kOptionEdgeScrollEdgeThickness, value: value.round().toString());
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
return _Card(title: 'Default Scroll Style', children: [
|
||||
_Radio(context,
|
||||
value: kRemoteScrollStyleAuto,
|
||||
groupValue: groupValue,
|
||||
label: 'ScrollAuto',
|
||||
onChanged: isOptFixed ? null : onChanged),
|
||||
_Radio(context,
|
||||
value: kRemoteScrollStyleEdge,
|
||||
groupValue: groupValue,
|
||||
label: 'ScrollEdge',
|
||||
onChanged: isOptFixed ? null : onChanged),
|
||||
_Radio(context,
|
||||
value: kRemoteScrollStyleBar,
|
||||
groupValue: groupValue,
|
||||
label: 'Scrollbar',
|
||||
onChanged: isOptFixed ? null : onChanged),
|
||||
_Radio(context,
|
||||
value: kRemoteScrollStyleEdge,
|
||||
groupValue: groupValue,
|
||||
label: 'ScrollEdge',
|
||||
onChanged: isOptFixed ? null : onChanged),
|
||||
Offstage(
|
||||
offstage: groupValue != kRemoteScrollStyleEdge,
|
||||
child: EdgeThicknessControl(
|
||||
value: double.tryParse(bind.mainGetUserDefaultOption(
|
||||
key: kOptionEdgeScrollEdgeThickness)) ??
|
||||
100.0,
|
||||
onChanged: isOptionFixed(kOptionEdgeScrollEdgeThickness)
|
||||
? null
|
||||
: onEdgeScrollEdgeThicknessChanged,
|
||||
)),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -511,7 +511,7 @@ class _MonitorMenu extends StatelessWidget {
|
||||
menuStyle: MenuStyle(
|
||||
padding:
|
||||
MaterialStatePropertyAll(EdgeInsets.symmetric(horizontal: 6))),
|
||||
menuChildrenGetter: () => [buildMonitorSubmenuWidget(context)]);
|
||||
menuChildrenGetter: (_) => [buildMonitorSubmenuWidget(context)]);
|
||||
}
|
||||
|
||||
Widget buildMultiMonitorMenu(BuildContext context) {
|
||||
@@ -722,7 +722,7 @@ class _ControlMenu extends StatelessWidget {
|
||||
color: _ToolbarTheme.blueColor,
|
||||
hoverColor: _ToolbarTheme.hoverBlueColor,
|
||||
ffi: ffi,
|
||||
menuChildrenGetter: () => toolbarControls(context, id, ffi).map((e) {
|
||||
menuChildrenGetter: (_) => toolbarControls(context, id, ffi).map((e) {
|
||||
if (e.divider) {
|
||||
return Divider();
|
||||
} else {
|
||||
@@ -933,12 +933,13 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
_screenAdjustor.updateScreen();
|
||||
menuChildrenGetter() {
|
||||
menuChildrenGetter(_IconSubmenuButtonState state) {
|
||||
final menuChildren = <Widget>[
|
||||
_screenAdjustor.adjustWindow(context),
|
||||
viewStyle(customPercent: _customPercent),
|
||||
scrollStyle(),
|
||||
scrollStyle(state, colorScheme),
|
||||
imageQuality(),
|
||||
codec(),
|
||||
if (ffi.connType == ConnType.defaultConn)
|
||||
@@ -1013,14 +1014,14 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
return Column(children: [
|
||||
...v.map((e) {
|
||||
final isCustom = e.value == kRemoteViewStyleCustom;
|
||||
final child = isCustom
|
||||
? Text(translate('Scale custom'))
|
||||
: e.child;
|
||||
final child =
|
||||
isCustom ? Text(translate('Scale custom')) : e.child;
|
||||
// Whether the current selection is already custom
|
||||
final bool isGroupCustomSelected =
|
||||
e.groupValue == kRemoteViewStyleCustom;
|
||||
// Keep menu open when switching INTO custom so the slider is visible immediately
|
||||
final bool keepOpenForThisItem = isCustom && !isGroupCustomSelected;
|
||||
final bool keepOpenForThisItem =
|
||||
isCustom && !isGroupCustomSelected;
|
||||
return RdoMenuButton<String>(
|
||||
value: e.value,
|
||||
groupValue: e.groupValue,
|
||||
@@ -1039,7 +1040,8 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
}).toList(),
|
||||
// Only show a divider when custom is NOT selected
|
||||
if (!isCustomSelected) Divider(),
|
||||
_customControlsIfCustomSelected(onChanged: (v) => customPercent.value = v),
|
||||
_customControlsIfCustomSelected(
|
||||
onChanged: (v) => customPercent.value = v),
|
||||
]);
|
||||
});
|
||||
}
|
||||
@@ -1054,12 +1056,14 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
duration: Duration(milliseconds: 220),
|
||||
switchInCurve: Curves.easeOut,
|
||||
switchOutCurve: Curves.easeIn,
|
||||
child: isCustom ? _CustomScaleMenuControls(ffi: ffi, onChanged: onChanged) : SizedBox.shrink(),
|
||||
child: isCustom
|
||||
? _CustomScaleMenuControls(ffi: ffi, onChanged: onChanged)
|
||||
: SizedBox.shrink(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
scrollStyle() {
|
||||
scrollStyle(_IconSubmenuButtonState state, ColorScheme colorScheme) {
|
||||
return futureBuilder(future: () async {
|
||||
final viewStyle =
|
||||
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
|
||||
@@ -1067,16 +1071,34 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
viewStyle == kRemoteViewStyleCustom;
|
||||
final scrollStyle =
|
||||
await bind.sessionGetScrollStyle(sessionId: ffi.sessionId) ?? '';
|
||||
return {'visible': visible, 'scrollStyle': scrollStyle};
|
||||
final edgeScrollEdgeThickness = await bind
|
||||
.sessionGetEdgeScrollEdgeThickness(sessionId: ffi.sessionId);
|
||||
return {
|
||||
'visible': visible,
|
||||
'scrollStyle': scrollStyle,
|
||||
'edgeScrollEdgeThickness': edgeScrollEdgeThickness,
|
||||
};
|
||||
}(), hasData: (data) {
|
||||
final visible = data['visible'] as bool;
|
||||
if (!visible) return Offstage();
|
||||
final groupValue = data['scrollStyle'] as String;
|
||||
onChange(String? value) async {
|
||||
final edgeScrollEdgeThickness = data['edgeScrollEdgeThickness'] as int;
|
||||
|
||||
onChangeScrollStyle(String? value) async {
|
||||
if (value == null) return;
|
||||
await bind.sessionSetScrollStyle(
|
||||
sessionId: ffi.sessionId, value: value);
|
||||
widget.ffi.canvasModel.updateScrollStyle();
|
||||
state.setState(() {});
|
||||
}
|
||||
|
||||
onChangeEdgeScrollEdgeThickness(double? value) async {
|
||||
if (value == null) return;
|
||||
final newThickness = value.round();
|
||||
await bind.sessionSetEdgeScrollEdgeThickness(
|
||||
sessionId: ffi.sessionId, value: newThickness);
|
||||
widget.ffi.canvasModel.updateEdgeScrollEdgeThickness(newThickness);
|
||||
state.setState(() {});
|
||||
}
|
||||
|
||||
return Obx(() => Column(children: [
|
||||
@@ -1085,17 +1107,9 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
value: kRemoteScrollStyleAuto,
|
||||
groupValue: groupValue,
|
||||
onChanged: widget.ffi.canvasModel.imageOverflow.value
|
||||
? (value) => onChange(value)
|
||||
: null,
|
||||
ffi: widget.ffi,
|
||||
),
|
||||
RdoMenuButton<String>(
|
||||
child: Text(translate('ScrollEdge')),
|
||||
value: kRemoteScrollStyleEdge,
|
||||
groupValue: groupValue,
|
||||
onChanged: widget.ffi.canvasModel.imageOverflow.value
|
||||
? (value) => onChange(value)
|
||||
? (value) => onChangeScrollStyle(value)
|
||||
: null,
|
||||
closeOnActivate: groupValue != kRemoteScrollStyleEdge,
|
||||
ffi: widget.ffi,
|
||||
),
|
||||
RdoMenuButton<String>(
|
||||
@@ -1103,10 +1117,28 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
value: kRemoteScrollStyleBar,
|
||||
groupValue: groupValue,
|
||||
onChanged: widget.ffi.canvasModel.imageOverflow.value
|
||||
? (value) => onChange(value)
|
||||
? (value) => onChangeScrollStyle(value)
|
||||
: null,
|
||||
closeOnActivate: groupValue != kRemoteScrollStyleEdge,
|
||||
ffi: widget.ffi,
|
||||
),
|
||||
RdoMenuButton<String>(
|
||||
child: Text(translate('ScrollEdge')),
|
||||
value: kRemoteScrollStyleEdge,
|
||||
groupValue: groupValue,
|
||||
closeOnActivate: false,
|
||||
onChanged: widget.ffi.canvasModel.imageOverflow.value
|
||||
? (value) => onChangeScrollStyle(value)
|
||||
: null,
|
||||
ffi: widget.ffi,
|
||||
),
|
||||
Offstage(
|
||||
offstage: groupValue != kRemoteScrollStyleEdge,
|
||||
child: EdgeThicknessControl(
|
||||
value: edgeScrollEdgeThickness.toDouble(),
|
||||
onChanged: onChangeEdgeScrollEdgeThickness,
|
||||
colorScheme: colorScheme,
|
||||
)),
|
||||
Divider(),
|
||||
]));
|
||||
});
|
||||
@@ -1193,13 +1225,16 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
||||
class _CustomScaleMenuControls extends StatefulWidget {
|
||||
final FFI ffi;
|
||||
final ValueChanged<int>? onChanged;
|
||||
const _CustomScaleMenuControls({Key? key, required this.ffi, this.onChanged}) : super(key: key);
|
||||
const _CustomScaleMenuControls({Key? key, required this.ffi, this.onChanged})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<_CustomScaleMenuControls> createState() => _CustomScaleMenuControlsState();
|
||||
State<_CustomScaleMenuControls> createState() =>
|
||||
_CustomScaleMenuControlsState();
|
||||
}
|
||||
|
||||
class _CustomScaleMenuControlsState extends CustomScaleControls<_CustomScaleMenuControls> {
|
||||
class _CustomScaleMenuControlsState
|
||||
extends CustomScaleControls<_CustomScaleMenuControls> {
|
||||
@override
|
||||
FFI get ffi => widget.ffi;
|
||||
|
||||
@@ -1235,7 +1270,9 @@ class _CustomScaleMenuControlsState extends CustomScaleControls<_CustomScaleMenu
|
||||
max: 1.0,
|
||||
// Use a wide range of divisions (calculated as (CustomScaleControls.maxPercent - CustomScaleControls.minPercent)) to provide ~1% precision increments.
|
||||
// This allows users to set precise scale values. Lower values would require more fine-tuning via the +/- buttons, which is undesirable for big ranges.
|
||||
divisions: (CustomScaleControls.maxPercent - CustomScaleControls.minPercent).round(),
|
||||
divisions:
|
||||
(CustomScaleControls.maxPercent - CustomScaleControls.minPercent)
|
||||
.round(),
|
||||
onChanged: onSliderChanged,
|
||||
),
|
||||
),
|
||||
@@ -1281,6 +1318,7 @@ class _RectValueThumbShape extends SliderComponentShape {
|
||||
final double width;
|
||||
final double height;
|
||||
final double radius;
|
||||
final String unit;
|
||||
// Optional mapper to compute display value from normalized position [0,1]
|
||||
// If null, falls back to linear interpolation between min and max.
|
||||
final int Function(double normalized)? displayValueForNormalized;
|
||||
@@ -1292,6 +1330,7 @@ class _RectValueThumbShape extends SliderComponentShape {
|
||||
required this.height,
|
||||
required this.radius,
|
||||
this.displayValueForNormalized,
|
||||
this.unit = '%',
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -1332,12 +1371,12 @@ class _RectValueThumbShape extends SliderComponentShape {
|
||||
final Paint paint = Paint()..color = fillColor;
|
||||
canvas.drawRRect(rrect, paint);
|
||||
|
||||
// Compute displayed percent from normalized slider value.
|
||||
final int percent = displayValueForNormalized != null
|
||||
// Compute displayed value from normalized slider value.
|
||||
final int displayValue = displayValueForNormalized != null
|
||||
? displayValueForNormalized!(value)
|
||||
: (min + value * (max - min)).round();
|
||||
final TextSpan span = TextSpan(
|
||||
text: '$percent%',
|
||||
text: '$displayValue$unit',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
@@ -1350,7 +1389,8 @@ class _RectValueThumbShape extends SliderComponentShape {
|
||||
textDirection: textDirection,
|
||||
);
|
||||
tp.layout(maxWidth: width - 4);
|
||||
tp.paint(canvas, Offset(center.dx - tp.width / 2, center.dy - tp.height / 2));
|
||||
tp.paint(
|
||||
canvas, Offset(center.dx - tp.width / 2, center.dy - tp.height / 2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1696,7 +1736,7 @@ class _KeyboardMenu extends StatelessWidget {
|
||||
ffi: ffi,
|
||||
color: _ToolbarTheme.blueColor,
|
||||
hoverColor: _ToolbarTheme.hoverBlueColor,
|
||||
menuChildrenGetter: () => [
|
||||
menuChildrenGetter: (_) => [
|
||||
keyboardMode(),
|
||||
localKeyboardType(),
|
||||
inputSource(),
|
||||
@@ -1961,7 +2001,7 @@ class _ChatMenuState extends State<_ChatMenu> {
|
||||
ffi: widget.ffi,
|
||||
color: _ToolbarTheme.blueColor,
|
||||
hoverColor: _ToolbarTheme.hoverBlueColor,
|
||||
menuChildrenGetter: () => [textChat(), voiceCall()]);
|
||||
menuChildrenGetter: (_) => [textChat(), voiceCall()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2017,7 +2057,7 @@ class _VoiceCallMenu extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
menuChildrenGetter() {
|
||||
menuChildrenGetter(_IconSubmenuButtonState state) {
|
||||
final audioInput = AudioInput(
|
||||
builder: (devices, currentDevice, setDevice) {
|
||||
return Column(
|
||||
@@ -2217,7 +2257,7 @@ class _IconSubmenuButton extends StatefulWidget {
|
||||
final Widget? icon;
|
||||
final Color color;
|
||||
final Color hoverColor;
|
||||
final List<Widget> Function() menuChildrenGetter;
|
||||
final List<Widget> Function(_IconSubmenuButtonState state) menuChildrenGetter;
|
||||
final MenuStyle? menuStyle;
|
||||
final FFI? ffi;
|
||||
final double? width;
|
||||
@@ -2242,6 +2282,11 @@ class _IconSubmenuButton extends StatefulWidget {
|
||||
class _IconSubmenuButtonState extends State<_IconSubmenuButton> {
|
||||
bool hover = false;
|
||||
|
||||
@override // discard @protected
|
||||
void setState(VoidCallback fn) {
|
||||
super.setState(fn);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(widget.svg != null || widget.icon != null);
|
||||
@@ -2274,7 +2319,7 @@ class _IconSubmenuButtonState extends State<_IconSubmenuButton> {
|
||||
),
|
||||
child: icon))),
|
||||
menuChildren: widget
|
||||
.menuChildrenGetter()
|
||||
.menuChildrenGetter(this)
|
||||
.map((e) => _buildPointerTrackWidget(e, widget.ffi))
|
||||
.toList()));
|
||||
return MenuBar(children: [
|
||||
@@ -2637,3 +2682,56 @@ Widget _buildPointerTrackWidget(Widget child, FFI? ffi) {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class EdgeThicknessControl extends StatelessWidget {
|
||||
final double value;
|
||||
final ValueChanged<double>? onChanged;
|
||||
final ColorScheme? colorScheme;
|
||||
|
||||
const EdgeThicknessControl({
|
||||
Key? key,
|
||||
required this.value,
|
||||
this.onChanged,
|
||||
this.colorScheme,
|
||||
}) : super(key: key);
|
||||
|
||||
static const double kMin = 20;
|
||||
static const double kMax = 150;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = this.colorScheme ?? Theme.of(context).colorScheme;
|
||||
|
||||
final slider = SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
activeTrackColor: colorScheme.primary,
|
||||
thumbColor: colorScheme.primary,
|
||||
overlayColor: colorScheme.primary.withOpacity(0.1),
|
||||
showValueIndicator: ShowValueIndicator.never,
|
||||
thumbShape: _RectValueThumbShape(
|
||||
min: EdgeThicknessControl.kMin,
|
||||
max: EdgeThicknessControl.kMax,
|
||||
width: 52,
|
||||
height: 24,
|
||||
radius: 4,
|
||||
unit: 'px',
|
||||
),
|
||||
),
|
||||
child: Semantics(
|
||||
value: value.toInt().toString(),
|
||||
child: Slider(
|
||||
value: value,
|
||||
min: EdgeThicknessControl.kMin,
|
||||
max: EdgeThicknessControl.kMax,
|
||||
divisions:
|
||||
(EdgeThicknessControl.kMax - EdgeThicknessControl.kMin).round(),
|
||||
semanticFormatterCallback: (double newValue) =>
|
||||
"${newValue.round()}px",
|
||||
onChanged: onChanged,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return slider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1667,6 +1667,7 @@ class ImageModel with ChangeNotifier {
|
||||
if (isDesktop || isWebDesktop) {
|
||||
await parent.target?.canvasModel.updateViewStyle();
|
||||
await parent.target?.canvasModel.updateScrollStyle();
|
||||
await parent.target?.canvasModel.initializeEdgeScrollEdgeThickness();
|
||||
}
|
||||
if (parent.target != null) {
|
||||
await initializeCursorAndCanvas(parent.target!);
|
||||
@@ -1914,6 +1915,8 @@ class CanvasModel with ChangeNotifier {
|
||||
// scroll offset y percent
|
||||
double _scrollY = 0.0;
|
||||
ScrollStyle _scrollStyle = ScrollStyle.scrollauto;
|
||||
// edge scroll mode: trigger scrolling when the cursor is close to the edge of the view
|
||||
int _edgeScrollEdgeThickness = 100;
|
||||
// tracks whether edge scroll should be active, prevents spurious
|
||||
// scrolling when the cursor enters the view from outside
|
||||
EdgeScrollState _edgeScrollState = EdgeScrollState.inactive;
|
||||
@@ -2090,11 +2093,11 @@ class CanvasModel with ChangeNotifier {
|
||||
});
|
||||
}
|
||||
|
||||
updateScrollStyle() async {
|
||||
Future<void> updateScrollStyle() async {
|
||||
final style = await bind.sessionGetScrollStyle(sessionId: sessionId);
|
||||
|
||||
_scrollStyle = style != null
|
||||
? ScrollStyle.fromString(style!)
|
||||
? ScrollStyle.fromString(style)
|
||||
: ScrollStyle.scrollauto;
|
||||
|
||||
if (_scrollStyle != ScrollStyle.scrollauto) {
|
||||
@@ -2104,7 +2107,20 @@ class CanvasModel with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
update(double x, double y, double scale) {
|
||||
Future<void> initializeEdgeScrollEdgeThickness() async {
|
||||
final savedValue = await bind.sessionGetEdgeScrollEdgeThickness(sessionId: sessionId);
|
||||
|
||||
if (savedValue != null) {
|
||||
_edgeScrollEdgeThickness = savedValue;
|
||||
}
|
||||
}
|
||||
|
||||
void updateEdgeScrollEdgeThickness(int newThickness) {
|
||||
_edgeScrollEdgeThickness = newThickness;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void update(double x, double y, double scale) {
|
||||
_x = x;
|
||||
_y = y;
|
||||
_scale = scale;
|
||||
@@ -2224,9 +2240,6 @@ class CanvasModel with ChangeNotifier {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger scrolling when the cursor is close to an edge
|
||||
const double edgeThickness = 100;
|
||||
|
||||
if (_edgeScrollState == EdgeScrollState.armed) {
|
||||
// Edge scroll is armed to become active once the cursor
|
||||
// is observed within the rectangle interior to the
|
||||
@@ -2235,7 +2248,7 @@ class CanvasModel with ChangeNotifier {
|
||||
// doesn't happen yet.
|
||||
final clientArea = Rect.fromLTWH(0, 0, size.width, size.height);
|
||||
|
||||
final innerZone = clientArea.deflate(edgeThickness);
|
||||
final innerZone = clientArea.deflate(_edgeScrollEdgeThickness.toDouble());
|
||||
|
||||
if (innerZone.contains(Offset(x, y))) {
|
||||
_edgeScrollState = EdgeScrollState.active;
|
||||
@@ -2248,16 +2261,16 @@ class CanvasModel with ChangeNotifier {
|
||||
var dxOffset = 0.0;
|
||||
var dyOffset = 0.0;
|
||||
|
||||
if (x < edgeThickness) {
|
||||
dxOffset = x - edgeThickness;
|
||||
} else if (x >= size.width - edgeThickness) {
|
||||
dxOffset = x - (size.width - edgeThickness);
|
||||
if (x < _edgeScrollEdgeThickness) {
|
||||
dxOffset = x - _edgeScrollEdgeThickness;
|
||||
} else if (x >= size.width - _edgeScrollEdgeThickness) {
|
||||
dxOffset = x - (size.width - _edgeScrollEdgeThickness);
|
||||
}
|
||||
|
||||
if (y < edgeThickness) {
|
||||
dyOffset = y - edgeThickness;
|
||||
} else if (y >= size.height - edgeThickness) {
|
||||
dyOffset = y - (size.height - edgeThickness);
|
||||
if (y < _edgeScrollEdgeThickness) {
|
||||
dyOffset = y - _edgeScrollEdgeThickness;
|
||||
} else if (y >= size.height - _edgeScrollEdgeThickness) {
|
||||
dyOffset = y - (size.height - _edgeScrollEdgeThickness);
|
||||
}
|
||||
|
||||
var encroachment = Vector2(dxOffset, dyOffset);
|
||||
@@ -3580,6 +3593,7 @@ class FFI {
|
||||
dialogManager.dismissAll();
|
||||
await canvasModel.updateViewStyle();
|
||||
await canvasModel.updateScrollStyle();
|
||||
await canvasModel.initializeEdgeScrollEdgeThickness();
|
||||
for (final cb in imageModel.callbacksOnFirstImage) {
|
||||
cb(id);
|
||||
}
|
||||
|
||||
Submodule libs/hbb_common updated: a4053b929b...9b53baeffe
@@ -1976,13 +1976,24 @@ impl LoginConfigHandler {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `value` - The view style to be saved.
|
||||
/// * `value` - The scroll style to be saved.
|
||||
pub fn save_scroll_style(&mut self, value: String) {
|
||||
let mut config = self.load_config();
|
||||
config.scroll_style = value;
|
||||
self.save_config(config);
|
||||
}
|
||||
|
||||
/// Save edge scroll edge thickness to the current config.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `value` - The edge thickness to be saved.
|
||||
pub fn save_edge_scroll_edge_thickness(&mut self, value: i32) {
|
||||
let mut config = self.load_config();
|
||||
config.edge_scroll_edge_thickness = value;
|
||||
self.save_config(config);
|
||||
}
|
||||
|
||||
/// Set a ui config of flutter for handler's [`PeerConfig`].
|
||||
///
|
||||
/// # Arguments
|
||||
|
||||
@@ -273,7 +273,10 @@ pub fn session_take_screenshot(session_id: SessionID, display: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_handle_screenshot(#[allow(unused_variables)] session_id: SessionID, action: String) -> String {
|
||||
pub fn session_handle_screenshot(
|
||||
#[allow(unused_variables)] session_id: SessionID,
|
||||
action: String,
|
||||
) -> String {
|
||||
crate::client::screenshot::handle_screenshot(action)
|
||||
}
|
||||
|
||||
@@ -393,6 +396,20 @@ pub fn session_set_scroll_style(session_id: SessionID, value: String) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_get_edge_scroll_edge_thickness(session_id: SessionID) -> Option<i32> {
|
||||
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||
Some(session.get_edge_scroll_edge_thickness())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_set_edge_scroll_edge_thickness(session_id: SessionID, value: i32) {
|
||||
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||
session.save_edge_scroll_edge_thickness(value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_get_image_quality(session_id: SessionID) -> Option<String> {
|
||||
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
|
||||
Some(session.get_image_quality())
|
||||
|
||||
@@ -238,6 +238,10 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
self.lc.read().unwrap().scroll_style.clone()
|
||||
}
|
||||
|
||||
pub fn get_edge_scroll_edge_thickness(&self) -> i32 {
|
||||
self.lc.read().unwrap().edge_scroll_edge_thickness
|
||||
}
|
||||
|
||||
pub fn get_image_quality(&self) -> String {
|
||||
self.lc.read().unwrap().image_quality.clone()
|
||||
}
|
||||
@@ -350,6 +354,10 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
self.lc.write().unwrap().save_scroll_style(value);
|
||||
}
|
||||
|
||||
pub fn save_edge_scroll_edge_thickness(&self, value: i32) {
|
||||
self.lc.write().unwrap().save_edge_scroll_edge_thickness(value);
|
||||
}
|
||||
|
||||
pub fn save_flutter_option(&self, k: String, v: String) {
|
||||
self.lc.write().unwrap().save_ui_flutter(k, v);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user