feat(canvas): canvas margin options
Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
a5a9c26e17
commit
4f301fe427
3 changed files with 100 additions and 83 deletions
|
|
@ -13,7 +13,6 @@ 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/model.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:flutter_hbb/models/printer_model.dart';
|
||||
import 'package:flutter_hbb/models/server_model.dart';
|
||||
|
|
@ -1813,21 +1812,25 @@ class _DisplayState extends State<_Display> {
|
|||
}
|
||||
|
||||
Widget remoteCanvasMargin(BuildContext context) {
|
||||
final canvasModel = Provider.of<CanvasModel>(context, listen: false);
|
||||
onChanged(double value) async {
|
||||
await canvasModel.setRemoteCanvasMargin(value);
|
||||
final normalizedValue = value.clamp(0, 400).round();
|
||||
await bind.mainSetUserDefaultOption(
|
||||
key: kOptionRemoteCanvasMargin, value: normalizedValue.toString());
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
final currentValue = canvasModel.remoteCanvasMargin;
|
||||
final currentValue = (double.tryParse(bind.mainGetUserDefaultOption(
|
||||
key: kOptionRemoteCanvasMargin)) ??
|
||||
0)
|
||||
.clamp(0, 400)
|
||||
.toDouble();
|
||||
|
||||
return _Card(title: 'Remote canvas margin', children: [
|
||||
return _Card(title: 'canvas_margin', children: [
|
||||
EdgeThicknessControl(
|
||||
value: currentValue,
|
||||
min: 0,
|
||||
max: 400,
|
||||
onChanged:
|
||||
isOptionFixed(kOptionRemoteCanvasMargin) ? null : onChanged,
|
||||
onChanged: onChanged,
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1104,32 +1104,24 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||
return futureBuilder(future: () async {
|
||||
final viewStyle =
|
||||
await bind.sessionGetViewStyle(sessionId: ffi.sessionId) ?? '';
|
||||
final visible = viewStyle == kRemoteViewStyleOriginal ||
|
||||
final scrollVisible = viewStyle == kRemoteViewStyleOriginal ||
|
||||
viewStyle == kRemoteViewStyleCustom;
|
||||
final scrollStyle =
|
||||
await bind.sessionGetScrollStyle(sessionId: ffi.sessionId) ?? '';
|
||||
final edgeScrollEdgeThickness = await bind
|
||||
.sessionGetEdgeScrollEdgeThickness(sessionId: ffi.sessionId);
|
||||
final remoteCanvasMargin =
|
||||
(double.tryParse(bind.mainGetUserDefaultOption(
|
||||
key: kOptionRemoteCanvasMargin)) ??
|
||||
0)
|
||||
.clamp(0, 400)
|
||||
.toDouble();
|
||||
await widget.ffi.canvasModel.initializeRemoteCanvasMargin();
|
||||
return {
|
||||
'visible': visible,
|
||||
'scrollVisible': scrollVisible,
|
||||
'scrollStyle': scrollStyle,
|
||||
'edgeScrollEdgeThickness': edgeScrollEdgeThickness,
|
||||
'remoteCanvasMargin': remoteCanvasMargin,
|
||||
'remoteCanvasMargin': widget.ffi.canvasModel.remoteCanvasMargin,
|
||||
};
|
||||
}(), hasData: (data) {
|
||||
final visible = data['visible'] as bool;
|
||||
if (!visible) return Offstage();
|
||||
final scrollVisible = data['scrollVisible'] as bool;
|
||||
final groupValue = data['scrollStyle'] as String;
|
||||
final edgeScrollEdgeThickness = data['edgeScrollEdgeThickness'] as int;
|
||||
final remoteCanvasMargin = data['remoteCanvasMargin'] as double;
|
||||
final isRemoteCanvasMarginFixed =
|
||||
isOptionFixed(kOptionRemoteCanvasMargin);
|
||||
|
||||
onChangeScrollStyle(String? value) async {
|
||||
if (value == null) return;
|
||||
|
|
@ -1149,73 +1141,73 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||
}
|
||||
|
||||
onChangeRemoteCanvasMargin(double? value) async {
|
||||
if (value == null || isRemoteCanvasMarginFixed) return;
|
||||
if (value == null) return;
|
||||
await widget.ffi.canvasModel.setRemoteCanvasMargin(value);
|
||||
state.setState(() {});
|
||||
}
|
||||
|
||||
return Obx(() => Column(children: [
|
||||
RdoMenuButton<String>(
|
||||
child: Text(translate('ScrollAuto')),
|
||||
value: kRemoteScrollStyleAuto,
|
||||
groupValue: groupValue,
|
||||
onChanged: widget.ffi.canvasModel.imageOverflow.value
|
||||
? (value) => onChangeScrollStyle(value)
|
||||
: null,
|
||||
closeOnActivate: groupValue != kRemoteScrollStyleEdge,
|
||||
ffi: widget.ffi,
|
||||
),
|
||||
RdoMenuButton<String>(
|
||||
child: Text(translate('Scrollbar')),
|
||||
value: kRemoteScrollStyleBar,
|
||||
groupValue: groupValue,
|
||||
onChanged: widget.ffi.canvasModel.imageOverflow.value
|
||||
? (value) => onChangeScrollStyle(value)
|
||||
: null,
|
||||
closeOnActivate: groupValue != kRemoteScrollStyleEdge,
|
||||
ffi: widget.ffi,
|
||||
),
|
||||
if (!isWeb) ...[
|
||||
RdoMenuButton<String>(
|
||||
child: Text(translate('ScrollEdge')),
|
||||
value: kRemoteScrollStyleEdge,
|
||||
return Column(children: [
|
||||
if (scrollVisible) ...[
|
||||
Obx(() => RdoMenuButton<String>(
|
||||
child: Text(translate('ScrollAuto')),
|
||||
value: kRemoteScrollStyleAuto,
|
||||
groupValue: groupValue,
|
||||
closeOnActivate: false,
|
||||
onChanged: widget.ffi.canvasModel.imageOverflow.value
|
||||
? (value) => onChangeScrollStyle(value)
|
||||
: null,
|
||||
closeOnActivate: groupValue != kRemoteScrollStyleEdge,
|
||||
ffi: widget.ffi,
|
||||
)),
|
||||
Obx(() => RdoMenuButton<String>(
|
||||
child: Text(translate('Scrollbar')),
|
||||
value: kRemoteScrollStyleBar,
|
||||
groupValue: groupValue,
|
||||
onChanged: widget.ffi.canvasModel.imageOverflow.value
|
||||
? (value) => onChangeScrollStyle(value)
|
||||
: null,
|
||||
closeOnActivate: groupValue != kRemoteScrollStyleEdge,
|
||||
ffi: widget.ffi,
|
||||
)),
|
||||
if (!isWeb) ...[
|
||||
Obx(() => 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,
|
||||
)),
|
||||
],
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: Text(translate('canvas_margin'))),
|
||||
SizedBox(
|
||||
width: 160,
|
||||
child: EdgeThicknessControl(
|
||||
value: remoteCanvasMargin,
|
||||
min: 0,
|
||||
max: 400,
|
||||
onChanged: onChangeRemoteCanvasMargin,
|
||||
colorScheme: colorScheme,
|
||||
),
|
||||
),
|
||||
Offstage(
|
||||
offstage: groupValue != kRemoteScrollStyleEdge,
|
||||
child: EdgeThicknessControl(
|
||||
value: edgeScrollEdgeThickness.toDouble(),
|
||||
onChanged: onChangeEdgeScrollEdgeThickness,
|
||||
colorScheme: colorScheme,
|
||||
)),
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: Text(translate('canvas_margin'))),
|
||||
SizedBox(
|
||||
width: 160,
|
||||
child: EdgeThicknessControl(
|
||||
value: remoteCanvasMargin,
|
||||
min: 0,
|
||||
max: 400,
|
||||
onChanged: isRemoteCanvasMarginFixed
|
||||
? null
|
||||
: onChangeRemoteCanvasMargin,
|
||||
colorScheme: colorScheme,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
]));
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2154,6 +2154,8 @@ class CanvasModel with ChangeNotifier {
|
|||
ScrollStyle _scrollStyle = ScrollStyle.scrollauto;
|
||||
// edge scroll mode: trigger scrolling when the cursor is close to the edge of the view
|
||||
int _edgeScrollEdgeThickness = 100;
|
||||
double _remoteCanvasMargin = 0;
|
||||
bool _remoteCanvasMarginInitialized = false;
|
||||
// tracks whether edge scroll should be active, prevents spurious
|
||||
// scrolling when the cursor enters the view from outside
|
||||
EdgeScrollState _edgeScrollState = EdgeScrollState.inactive;
|
||||
|
|
@ -2197,19 +2199,35 @@ class CanvasModel with ChangeNotifier {
|
|||
if (!(isDesktop || isWebDesktop)) {
|
||||
return 0;
|
||||
}
|
||||
final value =
|
||||
double.tryParse(bind.mainGetUserDefaultOption(key: kOptionRemoteCanvasMargin)) ??
|
||||
0;
|
||||
return min(400, max(0, value));
|
||||
return _remoteCanvasMargin;
|
||||
}
|
||||
|
||||
Future<void> setRemoteCanvasMargin(double value) async {
|
||||
final normalizedValue = value.clamp(0, 400).round();
|
||||
await bind.mainSetUserDefaultOption(
|
||||
key: kOptionRemoteCanvasMargin, value: normalizedValue.toString());
|
||||
await bind.sessionSetFlutterOption(
|
||||
sessionId: sessionId,
|
||||
k: kOptionRemoteCanvasMargin,
|
||||
v: normalizedValue.toString());
|
||||
_remoteCanvasMargin = normalizedValue.toDouble();
|
||||
_remoteCanvasMarginInitialized = true;
|
||||
await updateViewStyle();
|
||||
}
|
||||
|
||||
Future<void> initializeRemoteCanvasMargin() async {
|
||||
if (_remoteCanvasMarginInitialized || !(isDesktop || isWebDesktop)) {
|
||||
return;
|
||||
}
|
||||
final sessionValue = await bind.sessionGetFlutterOption(
|
||||
sessionId: sessionId, k: kOptionRemoteCanvasMargin);
|
||||
final defaultValue =
|
||||
bind.mainGetUserDefaultOption(key: kOptionRemoteCanvasMargin);
|
||||
final value =
|
||||
sessionValue?.isNotEmpty == true ? sessionValue : defaultValue;
|
||||
_remoteCanvasMargin =
|
||||
(double.tryParse(value ?? '') ?? 0).clamp(0, 400).toDouble();
|
||||
_remoteCanvasMarginInitialized = true;
|
||||
}
|
||||
|
||||
Rect? get paddedRect {
|
||||
final rect = realRect;
|
||||
if (rect == null) {
|
||||
|
|
@ -2328,6 +2346,7 @@ class CanvasModel with ChangeNotifier {
|
|||
return;
|
||||
}
|
||||
|
||||
await initializeRemoteCanvasMargin();
|
||||
updateSize();
|
||||
final displayWidth = getDisplayWidth();
|
||||
final displayHeight = getDisplayHeight();
|
||||
|
|
@ -2706,6 +2725,8 @@ class CanvasModel with ChangeNotifier {
|
|||
_y = 0;
|
||||
_scale = 1.0;
|
||||
_lastViewStyle = ViewStyle.defaultViewStyle();
|
||||
_remoteCanvasMargin = 0;
|
||||
_remoteCanvasMarginInitialized = false;
|
||||
_timerMobileFocusCanvasCursor?.cancel();
|
||||
_timerMobileRestoreCanvasOffset?.cancel();
|
||||
_offsetBeforeMobileSoftKeyboard = null;
|
||||
|
|
@ -3230,7 +3251,8 @@ class CursorModel with ChangeNotifier {
|
|||
dx = min(dx, maxCursorCanMove);
|
||||
}
|
||||
} else if (dx < 0) {
|
||||
final maxCanvasCanMove = (displayRect?.left ?? 0) - r.left.roundToDouble();
|
||||
final maxCanvasCanMove =
|
||||
(displayRect?.left ?? 0) - r.left.roundToDouble();
|
||||
tryMoveCanvasX = _x + dx < cx && maxCanvasCanMove < 0;
|
||||
if (tryMoveCanvasX) {
|
||||
dx = max(dx, maxCanvasCanMove);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue