Merge pull request #1273 from fufesou/flutter_desktop_remote_menus_rebase

Flutter desktop remote menus rebase
This commit is contained in:
RustDesk 2022-08-14 19:16:54 +08:00 committed by GitHub
commit f812adedff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 634 additions and 426 deletions

View File

@ -4,3 +4,6 @@ const String kAppTypeDesktopRemote = "remote";
const String kAppTypeDesktopFileTransfer = "file transfer"; const String kAppTypeDesktopFileTransfer = "file transfer";
const String kTabLabelHomePage = "Home"; const String kTabLabelHomePage = "Home";
const String kTabLabelSettingPage = "Settings"; const String kTabLabelSettingPage = "Settings";
const int kDefaultDisplayWidth = 1280;
const int kDefaultDisplayHeight = 720;

View File

@ -41,6 +41,7 @@ class _RemotePageState extends State<RemotePage>
String _value = ''; String _value = '';
double _scale = 1; double _scale = 1;
double _mouseScrollIntegral = 0; // mouse scroll speed controller double _mouseScrollIntegral = 0; // mouse scroll speed controller
var _cursorOverImage = false.obs;
var _more = true; var _more = true;
var _fn = false; var _fn = false;
@ -256,7 +257,8 @@ class _RemotePageState extends State<RemotePage>
} }
}); });
}), }),
bottomNavigationBar: _showBar && hasDisplays ? getBottomAppBar() : null, bottomNavigationBar:
_showBar && hasDisplays ? getBottomAppBar(ffiModel) : null,
body: Overlay( body: Overlay(
initialEntries: [ initialEntries: [
OverlayEntry(builder: (context) { OverlayEntry(builder: (context) {
@ -274,7 +276,6 @@ class _RemotePageState extends State<RemotePage>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
_ffi.canvasModel.tabBarHeight = super.widget.tabBarHeight;
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
clientClose(_ffi.dialogManager); clientClose(_ffi.dialogManager);
@ -292,62 +293,7 @@ class _RemotePageState extends State<RemotePage>
} }
Widget getRawPointerAndKeyBody(Widget child) { Widget getRawPointerAndKeyBody(Widget child) {
return Listener( return Consumer<FfiModel>(
onPointerHover: (e) {
if (e.kind != ui.PointerDeviceKind.mouse) return;
if (!_isPhysicalMouse) {
setState(() {
_isPhysicalMouse = true;
});
}
if (_isPhysicalMouse) {
_ffi.handleMouse(getEvent(e, 'mousemove'),
tabBarHeight: super.widget.tabBarHeight);
}
},
onPointerDown: (e) {
if (e.kind != ui.PointerDeviceKind.mouse) {
if (_isPhysicalMouse) {
setState(() {
_isPhysicalMouse = false;
});
}
}
if (_isPhysicalMouse) {
_ffi.handleMouse(getEvent(e, 'mousedown'),
tabBarHeight: super.widget.tabBarHeight);
}
},
onPointerUp: (e) {
if (e.kind != ui.PointerDeviceKind.mouse) return;
if (_isPhysicalMouse) {
_ffi.handleMouse(getEvent(e, 'mouseup'),
tabBarHeight: super.widget.tabBarHeight);
}
},
onPointerMove: (e) {
if (e.kind != ui.PointerDeviceKind.mouse) return;
if (_isPhysicalMouse) {
_ffi.handleMouse(getEvent(e, 'mousemove'),
tabBarHeight: super.widget.tabBarHeight);
}
},
onPointerSignal: (e) {
if (e is PointerScrollEvent) {
var dx = e.scrollDelta.dx;
var dy = e.scrollDelta.dy;
if (dx > 0)
dx = -1;
else if (dx < 0) dx = 1;
if (dy > 0)
dy = -1;
else if (dy < 0) dy = 1;
bind.sessionSendMouse(
id: widget.id,
msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}');
}
},
child: Consumer<FfiModel>(
builder: (context, FfiModel, _child) => MouseRegion( builder: (context, FfiModel, _child) => MouseRegion(
cursor: FfiModel.permissions['keyboard'] != false cursor: FfiModel.permissions['keyboard'] != false
? SystemMouseCursors.none ? SystemMouseCursors.none
@ -395,11 +341,13 @@ class _RemotePageState extends State<RemotePage>
} }
return KeyEventResult.handled; return KeyEventResult.handled;
}, },
child: child))))); child: child))));
} }
Widget? getBottomAppBar() { Widget? getBottomAppBar(FfiModel ffiModel) {
return BottomAppBar( return MouseRegion(
cursor: SystemMouseCursors.basic,
child: BottomAppBar(
elevation: 10, elevation: 10,
color: MyTheme.accent, color: MyTheme.accent,
child: Row( child: Row(
@ -474,7 +422,7 @@ class _RemotePageState extends State<RemotePage>
icon: Icon(Icons.more_vert), icon: Icon(Icons.more_vert),
onPressed: () { onPressed: () {
setState(() => _showEdit = false); setState(() => _showEdit = false);
showActions(widget.id); showActions(widget.id, ffiModel);
}, },
), ),
]), ]),
@ -486,7 +434,7 @@ class _RemotePageState extends State<RemotePage>
}), }),
], ],
), ),
); ));
} }
/// touchMode only: /// touchMode only:
@ -499,6 +447,81 @@ class _RemotePageState extends State<RemotePage>
/// DoubleFiner -> right click /// DoubleFiner -> right click
/// HoldDrag -> left drag /// HoldDrag -> left drag
void _onPointHoverImage(PointerHoverEvent e) {
if (e.kind != ui.PointerDeviceKind.mouse) return;
if (!_isPhysicalMouse) {
setState(() {
_isPhysicalMouse = true;
});
}
if (_isPhysicalMouse) {
_ffi.handleMouse(getEvent(e, 'mousemove'),
tabBarHeight: super.widget.tabBarHeight);
}
}
void _onPointDownImage(PointerDownEvent e) {
if (e.kind != ui.PointerDeviceKind.mouse) {
if (_isPhysicalMouse) {
setState(() {
_isPhysicalMouse = false;
});
}
}
if (_isPhysicalMouse) {
_ffi.handleMouse(getEvent(e, 'mousedown'),
tabBarHeight: super.widget.tabBarHeight);
}
}
void _onPointUpImage(PointerUpEvent e) {
if (e.kind != ui.PointerDeviceKind.mouse) return;
if (_isPhysicalMouse) {
_ffi.handleMouse(getEvent(e, 'mouseup'),
tabBarHeight: super.widget.tabBarHeight);
}
}
void _onPointMoveImage(PointerMoveEvent e) {
if (e.kind != ui.PointerDeviceKind.mouse) return;
if (_isPhysicalMouse) {
_ffi.handleMouse(getEvent(e, 'mousemove'),
tabBarHeight: super.widget.tabBarHeight);
}
}
void _onPointerSignalImage(PointerSignalEvent e) {
if (e is PointerScrollEvent) {
var dx = e.scrollDelta.dx.toInt();
var dy = e.scrollDelta.dy.toInt();
if (dx > 0)
dx = -1;
else if (dx < 0) dx = 1;
if (dy > 0)
dy = -1;
else if (dy < 0) dy = 1;
bind.sessionSendMouse(
id: widget.id, msg: '{"type": "wheel", "x": "$dx", "y": "$dy"}');
}
}
Widget _buildImageListener(Widget child) {
return Listener(
onPointerHover: _onPointHoverImage,
onPointerDown: _onPointDownImage,
onPointerUp: _onPointUpImage,
onPointerMove: _onPointMoveImage,
onPointerSignal: _onPointerSignalImage,
child: MouseRegion(
onEnter: (evt) {
_cursorOverImage.value = true;
},
onExit: (evt) {
_cursorOverImage.value = false;
},
child: child));
}
Widget getBodyForDesktop(BuildContext context, bool keyboard) { Widget getBodyForDesktop(BuildContext context, bool keyboard) {
var paints = <Widget>[ var paints = <Widget>[
MouseRegion(onEnter: (evt) { MouseRegion(onEnter: (evt) {
@ -512,6 +535,8 @@ class _RemotePageState extends State<RemotePage>
}); });
return ImagePaint( return ImagePaint(
id: widget.id, id: widget.id,
cursorOverImage: _cursorOverImage,
listenerBuilder: _buildImageListener,
); );
}), }),
)) ))
@ -550,7 +575,7 @@ class _RemotePageState extends State<RemotePage>
return out; return out;
} }
void showActions(String id) async { void showActions(String id, FfiModel ffiModel) async {
final size = MediaQuery.of(context).size; final size = MediaQuery.of(context).size;
final x = 120.0; final x = 120.0;
final y = size.height - super.widget.tabBarHeight; final y = size.height - super.widget.tabBarHeight;
@ -595,12 +620,8 @@ class _RemotePageState extends State<RemotePage>
await bind.getSessionToggleOption(id: id, arg: 'privacy-mode') != await bind.getSessionToggleOption(id: id, arg: 'privacy-mode') !=
true) { true) {
more.add(PopupMenuItem<String>( more.add(PopupMenuItem<String>(
child: Consumer<FfiModel>( child: Text(translate(
builder: (_context, ffiModel, _child) => () { (ffiModel.inputBlocked ? 'Unb' : 'B') + 'lock user input')),
return Text(translate(
(ffiModel.inputBlocked ? 'Unb' : 'B') +
'lock user input'));
}()),
value: 'block-input')); value: 'block-input'));
} }
} }
@ -630,6 +651,9 @@ class _RemotePageState extends State<RemotePage>
} }
}(); }();
} else if (value == 'enter_os_password') { } else if (value == 'enter_os_password') {
// FIXME:
// null means no session of id
// empty string means no password
var password = await bind.getSessionOption(id: id, arg: "os-password"); var password = await bind.getSessionOption(id: id, arg: "os-password");
if (password != null) { if (password != null) {
bind.sessionInputOsPassword(id: widget.id, value: password); bind.sessionInputOsPassword(id: widget.id, value: password);
@ -822,18 +846,95 @@ class _RemotePageState extends State<RemotePage>
class ImagePaint extends StatelessWidget { class ImagePaint extends StatelessWidget {
final String id; final String id;
final Rx<bool> cursorOverImage;
final Widget Function(Widget)? listenerBuilder;
final ScrollController _horizontal = ScrollController();
final ScrollController _vertical = ScrollController();
const ImagePaint({Key? key, required this.id}) : super(key: key); ImagePaint(
{Key? key,
required this.id,
required this.cursorOverImage,
this.listenerBuilder = null})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final m = Provider.of<ImageModel>(context); final m = Provider.of<ImageModel>(context);
final c = Provider.of<CanvasModel>(context); var c = Provider.of<CanvasModel>(context);
var s = c.scale; final s = c.scale;
return CustomPaint( if (c.scrollStyle == ScrollStyle.scrollbar) {
painter: final imageWidget = SizedBox(
new ImagePainter(image: m.image, x: c.x / s, y: c.y / s, scale: s), width: c.getDisplayWidth() * s,
); height: c.getDisplayHeight() * s,
child: CustomPaint(
painter: new ImagePainter(image: m.image, x: 0, y: 0, scale: s),
));
return Center(
child: NotificationListener<ScrollNotification>(
onNotification: (_notification) {
final percentX = _horizontal.position.extentBefore /
(_horizontal.position.extentBefore +
_horizontal.position.extentInside +
_horizontal.position.extentAfter);
final percentY = _vertical.position.extentBefore /
(_vertical.position.extentBefore +
_vertical.position.extentInside +
_vertical.position.extentAfter);
c.setScrollPercent(percentX, percentY);
return false;
},
child: Obx(() => MouseRegion(
cursor: cursorOverImage.value
? SystemMouseCursors.none
: SystemMouseCursors.basic,
child: _buildCrossScrollbar(_buildListener(imageWidget)))),
));
} else {
final imageWidget = SizedBox(
width: c.size.width,
height: c.size.height,
child: CustomPaint(
painter: new ImagePainter(
image: m.image, x: c.x / s, y: c.y / s, scale: s),
));
return _buildListener(imageWidget);
}
}
Widget _buildCrossScrollbar(Widget child) {
final physicsVertical =
cursorOverImage.value ? const NeverScrollableScrollPhysics() : null;
final physicsHorizontal =
cursorOverImage.value ? const NeverScrollableScrollPhysics() : null;
return Scrollbar(
controller: _vertical,
thumbVisibility: true,
trackVisibility: true,
child: Scrollbar(
controller: _horizontal,
thumbVisibility: true,
trackVisibility: true,
notificationPredicate: (notif) => notif.depth == 1,
child: SingleChildScrollView(
controller: _vertical,
physics: physicsVertical,
child: SingleChildScrollView(
controller: _horizontal,
scrollDirection: Axis.horizontal,
physics: physicsHorizontal,
child: child,
),
),
));
}
Widget _buildListener(Widget child) {
if (listenerBuilder != null) {
return listenerBuilder!(child);
} else {
return child;
}
} }
} }
@ -896,6 +997,8 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
if (quality == '') quality = 'balanced'; if (quality == '') quality = 'balanced';
String viewStyle = String viewStyle =
await bind.getSessionOption(id: id, arg: 'view-style') ?? ''; await bind.getSessionOption(id: id, arg: 'view-style') ?? '';
String scrollStyle =
await bind.getSessionOption(id: id, arg: 'scroll-style') ?? '';
var displays = <Widget>[]; var displays = <Widget>[];
final pi = ffi(id).ffiModel.pi; final pi = ffi(id).ffiModel.pi;
final image = ffi(id).ffiModel.getConnectionImage(); final image = ffi(id).ffiModel.getConnectionImage();
@ -968,6 +1071,14 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
ffi(id).canvasModel.updateViewStyle(); ffi(id).canvasModel.updateViewStyle();
}); });
}; };
var setScrollStyle = (String? value) {
if (value == null) return;
setState(() {
scrollStyle = value;
bind.sessionPeerOption(id: id, name: "scroll-style", value: value);
ffi(id).canvasModel.updateScrollStyle();
});
};
return CustomAlertDialog( return CustomAlertDialog(
title: SizedBox.shrink(), title: SizedBox.shrink(),
content: Column( content: Column(
@ -978,6 +1089,10 @@ void showOptions(String id, OverlayDialogManager dialogManager) async {
getRadio('Shrink', 'shrink', viewStyle, setViewStyle), getRadio('Shrink', 'shrink', viewStyle, setViewStyle),
getRadio('Stretch', 'stretch', viewStyle, setViewStyle), getRadio('Stretch', 'stretch', viewStyle, setViewStyle),
Divider(color: MyTheme.border), Divider(color: MyTheme.border),
getRadio(
'ScrollAuto', 'scrollauto', scrollStyle, setScrollStyle),
getRadio('Scrollbar', 'scrollbar', scrollStyle, setScrollStyle),
Divider(color: MyTheme.border),
getRadio('Good image quality', 'best', quality, setQuality), getRadio('Good image quality', 'best', quality, setQuality),
getRadio('Balanced', 'balanced', quality, setQuality), getRadio('Balanced', 'balanced', quality, setQuality),
getRadio('Optimize reaction time', 'low', quality, setQuality), getRadio('Optimize reaction time', 'low', quality, setQuality),

View File

@ -735,6 +735,9 @@ class _RemotePageState extends State<RemotePage> {
} }
}(); }();
} else if (value == 'enter_os_password') { } else if (value == 'enter_os_password') {
// FIXME:
// null means no session of id
// empty string means no password
var password = await bind.getSessionOption(id: id, arg: "os-password"); var password = await bind.getSessionOption(id: id, arg: "os-password");
if (password != null) { if (password != null) {
bind.sessionInputOsPassword(id: widget.id, value: password); bind.sessionInputOsPassword(id: widget.id, value: password);

View File

@ -387,8 +387,9 @@ class ImageModel with ChangeNotifier {
void update(ui.Image? image, double tabBarHeight) { void update(ui.Image? image, double tabBarHeight) {
if (_image == null && image != null) { if (_image == null && image != null) {
if (isWebDesktop) { if (isWebDesktop || isDesktop) {
parent.target?.canvasModel.updateViewStyle(); parent.target?.canvasModel.updateViewStyle();
parent.target?.canvasModel.updateScrollStyle();
} else { } else {
final size = MediaQueryData.fromWindow(ui.window).size; final size = MediaQueryData.fromWindow(ui.window).size;
final canvasWidth = size.width; final canvasWidth = size.width;
@ -432,36 +433,52 @@ class ImageModel with ChangeNotifier {
} }
} }
enum ScrollStyle {
scrollbar,
scrollauto,
}
class CanvasModel with ChangeNotifier { class CanvasModel with ChangeNotifier {
// scroll offset x percent
double _scrollX = 0.0;
// scroll offset y percent
double _scrollY = 0.0;
double _x = 0; double _x = 0;
double _y = 0; double _y = 0;
double _scale = 1.0; double _scale = 1.0;
double _tabBarHeight = 0.0; double _tabBarHeight = 0.0;
String id = ""; // TODO multi canvas model String id = ""; // TODO multi canvas model
ScrollStyle _scrollStyle = ScrollStyle.scrollauto;
WeakReference<FFI> parent; WeakReference<FFI> parent;
CanvasModel(this.parent); CanvasModel(this.parent);
double get x => _x; double get x => _x;
double get y => _y; double get y => _y;
double get scale => _scale; double get scale => _scale;
ScrollStyle get scrollStyle => _scrollStyle;
setScrollPercent(double x, double y) {
_scrollX = x;
_scrollY = y;
}
double get scrollX => _scrollX;
double get scrollY => _scrollY;
set tabBarHeight(double h) => _tabBarHeight = h; set tabBarHeight(double h) => _tabBarHeight = h;
double get tabBarHeight => _tabBarHeight; double get tabBarHeight => _tabBarHeight;
void updateViewStyle() async { void updateViewStyle() async {
final s = await bind.getSessionOption(id: id, arg: 'view-style'); final style = await bind.getSessionOption(id: id, arg: 'view-style');
if (s == null) { if (style == null) {
return; return;
} }
final size = MediaQueryData.fromWindow(ui.window).size;
final canvasWidth = size.width; final s1 = size.width / (parent.target?.ffiModel.display.width ?? 720);
final canvasHeight = size.height - _tabBarHeight; final s2 = size.height / (parent.target?.ffiModel.display.height ?? 1280);
final s1 = canvasWidth / (parent.target?.ffiModel.display.width ?? 720);
final s2 = canvasHeight / (parent.target?.ffiModel.display.height ?? 1280);
// Closure to perform shrink operation. // Closure to perform shrink operation.
final shrinkOp = () { final shrinkOp = () {
final s = s1 < s2 ? s1 : s2; final s = s1 < s2 ? s1 : s2;
@ -471,7 +488,7 @@ class CanvasModel with ChangeNotifier {
}; };
// Closure to perform stretch operation. // Closure to perform stretch operation.
final stretchOp = () { final stretchOp = () {
final s = s1 > s2 ? s1 : s2; final s = s1 < s2 ? s1 : s2;
if (s > 1) { if (s > 1) {
_scale = s; _scale = s;
} }
@ -480,20 +497,34 @@ class CanvasModel with ChangeNotifier {
final defaultOp = () { final defaultOp = () {
_scale = 1.0; _scale = 1.0;
}; };
if (s == 'shrink') {
shrinkOp(); // // On desktop, shrink is the default behavior.
} else if (s == 'stretch') { // if (isDesktop) {
stretchOp(); // shrinkOp();
} else { // } else {
// On desktop, shrink is the default behavior.
if (isDesktop) {
shrinkOp();
} else {
defaultOp(); defaultOp();
// }
if (style == 'shrink') {
shrinkOp();
} else if (style == 'stretch') {
stretchOp();
} }
_x = (size.width - getDisplayWidth() * _scale) / 2;
_y = (size.height - getDisplayHeight() * _scale) / 2;
notifyListeners();
}
updateScrollStyle() async {
final style = await bind.getSessionOption(id: id, arg: 'scroll-style');
if (style == 'scrollbar') {
_scrollStyle = ScrollStyle.scrollbar;
_scrollX = 0.0;
_scrollY = 0.0;
} else {
_scrollStyle = ScrollStyle.scrollauto;
} }
_x = (canvasWidth - getDisplayWidth() * _scale) / 2;
_y = (canvasHeight - getDisplayHeight() * _scale) / 2;
notifyListeners(); notifyListeners();
} }
@ -512,28 +543,30 @@ class CanvasModel with ChangeNotifier {
return parent.target?.ffiModel.display.height ?? 720; return parent.target?.ffiModel.display.height ?? 720;
} }
Size get size {
final size = MediaQueryData.fromWindow(ui.window).size;
return Size(size.width, size.height - _tabBarHeight);
}
void moveDesktopMouse(double x, double y) { void moveDesktopMouse(double x, double y) {
// On mobile platforms, move the canvas with the cursor. // On mobile platforms, move the canvas with the cursor.
if (!isDesktop) { //if (!isDesktop) {
final size = MediaQueryData.fromWindow(ui.window).size;
final canvasWidth = size.width;
final canvasHeight = size.height - _tabBarHeight;
final dw = getDisplayWidth() * _scale; final dw = getDisplayWidth() * _scale;
final dh = getDisplayHeight() * _scale; final dh = getDisplayHeight() * _scale;
var dxOffset = 0; var dxOffset = 0;
var dyOffset = 0; var dyOffset = 0;
if (dw > canvasWidth) { if (dw > size.width) {
dxOffset = (x - dw * (x / canvasWidth) - _x).toInt(); dxOffset = (x - dw * (x / size.width) - _x).toInt();
} }
if (dh > canvasHeight) { if (dh > size.height) {
dyOffset = (y - dh * (y / canvasHeight) - _y).toInt(); dyOffset = (y - dh * (y / size.height) - _y).toInt();
} }
_x += dxOffset; _x += dxOffset;
_y += dyOffset; _y += dyOffset;
if (dxOffset != 0 || dyOffset != 0) { if (dxOffset != 0 || dyOffset != 0) {
notifyListeners(); notifyListeners();
} }
} //}
parent.target?.cursorModel.moveLocal(x, y); parent.target?.cursorModel.moveLocal(x, y);
} }
@ -1091,8 +1124,24 @@ class FFI {
canvasModel.moveDesktopMouse(x, y); canvasModel.moveDesktopMouse(x, y);
} }
final d = ffiModel.display; final d = ffiModel.display;
if (canvasModel.scrollStyle == ScrollStyle.scrollbar) {
final imageWidth = d.width * canvasModel.scale;
final imageHeight = d.height * canvasModel.scale;
x += imageWidth * canvasModel.scrollX;
y += imageHeight * canvasModel.scrollY;
// boxed size is a center widget
if (canvasModel.size.width > imageWidth) {
x -= ((canvasModel.size.width - imageWidth) / 2);
}
if (canvasModel.size.height > imageHeight) {
y -= ((canvasModel.size.height - imageHeight) / 2);
}
} else {
x -= canvasModel.x; x -= canvasModel.x;
y -= canvasModel.y; y -= canvasModel.y;
}
if (!isMove && (x < 0 || x > d.width || y < 0 || y > d.height)) { if (!isMove && (x < 0 || x > d.width || y < 0 || y > d.height)) {
return; return;
} }

File diff suppressed because it is too large Load Diff

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "原始比例"), ("Original", "原始比例"),
("Shrink", "收缩"), ("Shrink", "收缩"),
("Stretch", "伸展"), ("Stretch", "伸展"),
("Scrollbar", "滚动条"),
("ScrollAuto", "自动滚动"),
("Good image quality", "好画质"), ("Good image quality", "好画质"),
("Balanced", "一般画质"), ("Balanced", "一般画质"),
("Optimize reaction time", "优化反应时间"), ("Optimize reaction time", "优化反应时间"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Původní"), ("Original", "Původní"),
("Shrink", "Oříznout"), ("Shrink", "Oříznout"),
("Stretch", "Roztáhnout"), ("Stretch", "Roztáhnout"),
("Scrollbar", "Posuvník"),
("ScrollAuto", "Rolovať Auto"),
("Good image quality", "Dobrá kvalita obrazu"), ("Good image quality", "Dobrá kvalita obrazu"),
("Balanced", "Vyvážené"), ("Balanced", "Vyvážené"),
("Optimize reaction time", "Optimalizovat pro co nejnižší prodlevu odezvy"), ("Optimize reaction time", "Optimalizovat pro co nejnižší prodlevu odezvy"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Original"), ("Original", "Original"),
("Shrink", "Krymp"), ("Shrink", "Krymp"),
("Stretch", "Strak"), ("Stretch", "Strak"),
("Scrollbar", "Rullebar"),
("ScrollAuto", "Rul Auto"),
("Good image quality", "God billedkvalitet"), ("Good image quality", "God billedkvalitet"),
("Balanced", "Afbalanceret"), ("Balanced", "Afbalanceret"),
("Optimize reaction time", "Optimeret responstid"), ("Optimize reaction time", "Optimeret responstid"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Original"), ("Original", "Original"),
("Shrink", "Verkleinern"), ("Shrink", "Verkleinern"),
("Stretch", "Strecken"), ("Stretch", "Strecken"),
("Scrollbar", "Scrollleiste"),
("ScrollAuto", "Automatisch scrollen"),
("Good image quality", "Schöner"), ("Good image quality", "Schöner"),
("Balanced", "Ausgeglichen"), ("Balanced", "Ausgeglichen"),
("Optimize reaction time", "Schneller"), ("Optimize reaction time", "Schneller"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Originala rilatumo"), ("Original", "Originala rilatumo"),
("Shrink", "Ŝrumpi"), ("Shrink", "Ŝrumpi"),
("Stretch", "Streĉi"), ("Stretch", "Streĉi"),
("Scrollbar", "Rulumbreto"),
("ScrollAuto", "Rulumu Aŭtomate"),
("Good image quality", "Bona bilda kvalito"), ("Good image quality", "Bona bilda kvalito"),
("Balanced", "Normala bilda kvalito"), ("Balanced", "Normala bilda kvalito"),
("Optimize reaction time", "Optimigi reakcia tempo"), ("Optimize reaction time", "Optimigi reakcia tempo"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Original"), ("Original", "Original"),
("Shrink", "Encogerse"), ("Shrink", "Encogerse"),
("Stretch", "Estirar"), ("Stretch", "Estirar"),
("Scrollbar", "Barra de desplazamiento"),
("ScrollAuto", "Desplazamiento automático"),
("Good image quality", "Buena calidad de imagen"), ("Good image quality", "Buena calidad de imagen"),
("Balanced", "Equilibrado"), ("Balanced", "Equilibrado"),
("Optimize reaction time", "Optimizar el tiempo de reacción"), ("Optimize reaction time", "Optimizar el tiempo de reacción"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Ratio d'origine"), ("Original", "Ratio d'origine"),
("Shrink", "Rétrécir"), ("Shrink", "Rétrécir"),
("Stretch", "Étirer"), ("Stretch", "Étirer"),
("Scrollbar", "Barre de défilement"),
("ScrollAuto", "Défilement automatique"),
("Good image quality", "Bonne qualité d'image"), ("Good image quality", "Bonne qualité d'image"),
("Balanced", "Qualité d'image normale"), ("Balanced", "Qualité d'image normale"),
("Optimize reaction time", "Optimiser le temps de réaction"), ("Optimize reaction time", "Optimiser le temps de réaction"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Eredeti"), ("Original", "Eredeti"),
("Shrink", "Zsugorított"), ("Shrink", "Zsugorított"),
("Stretch", "Nyújtott"), ("Stretch", "Nyújtott"),
("Scrollbar", "Görgetősáv"),
("ScrollAuto", "Görgessen Auto"),
("Good image quality", "Jó képminőség"), ("Good image quality", "Jó képminőség"),
("Balanced", "Balanszolt"), ("Balanced", "Balanszolt"),
("Optimize reaction time", "Válaszidő optimializálása"), ("Optimize reaction time", "Válaszidő optimializálása"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Original"), ("Original", "Original"),
("Shrink", "Susutkan"), ("Shrink", "Susutkan"),
("Stretch", "Regangkan"), ("Stretch", "Regangkan"),
("Scrollbar", "Scroll bar"),
("ScrollAuto", "Gulir Otomatis"),
("Good image quality", "Kualitas Gambar Baik"), ("Good image quality", "Kualitas Gambar Baik"),
("Balanced", "Seimbang"), ("Balanced", "Seimbang"),
("Optimize reaction time", "Optimalkan waktu reaksi"), ("Optimize reaction time", "Optimalkan waktu reaksi"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Originale"), ("Original", "Originale"),
("Shrink", "Restringi"), ("Shrink", "Restringi"),
("Stretch", "Allarga"), ("Stretch", "Allarga"),
("Scrollbar", "Barra di scorrimento"),
("ScrollAuto", "Scorri automaticamente"),
("Good image quality", "Buona qualità immagine"), ("Good image quality", "Buona qualità immagine"),
("Balanced", "Bilanciato"), ("Balanced", "Bilanciato"),
("Optimize reaction time", "Ottimizza il tempo di reazione"), ("Optimize reaction time", "Ottimizza il tempo di reazione"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "オリジナル"), ("Original", "オリジナル"),
("Shrink", "縮小"), ("Shrink", "縮小"),
("Stretch", "伸縮"), ("Stretch", "伸縮"),
("Scrollbar", "スクロール・バー"),
("ScrollAuto", "自動スクロール"),
("Good image quality", "画質優先"), ("Good image quality", "画質優先"),
("Balanced", "バランス"), ("Balanced", "バランス"),
("Optimize reaction time", "速度優先"), ("Optimize reaction time", "速度優先"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Oryginał"), ("Original", "Oryginał"),
("Shrink", "Zmniejsz"), ("Shrink", "Zmniejsz"),
("Stretch", "Zwiększ"), ("Stretch", "Zwiększ"),
("Scrollbar", "Pasek przewijania"),
("ScrollAuto", "Przewijanie automatyczne"),
("Good image quality", "Dobra jakość obrazu"), ("Good image quality", "Dobra jakość obrazu"),
("Balanced", "Zrównoważony"), ("Balanced", "Zrównoważony"),
("Optimize reaction time", "Zoptymalizuj czas reakcji"), ("Optimize reaction time", "Zoptymalizuj czas reakcji"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Original"), ("Original", "Original"),
("Shrink", "Reduzir"), ("Shrink", "Reduzir"),
("Stretch", "Aumentar"), ("Stretch", "Aumentar"),
("Scrollbar", "Barra de rolagem"),
("ScrollAuto", "Rolagem automática"),
("Good image quality", "Qualidade visual boa"), ("Good image quality", "Qualidade visual boa"),
("Balanced", "Balanceada"), ("Balanced", "Balanceada"),
("Optimize reaction time", "Otimizar tempo de reação"), ("Optimize reaction time", "Otimizar tempo de reação"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Оригинал"), ("Original", "Оригинал"),
("Shrink", "Уменьшить"), ("Shrink", "Уменьшить"),
("Stretch", "Растянуть"), ("Stretch", "Растянуть"),
("Scrollbar", "Полоса прокрутки"),
("ScrollAuto", "Прокрутка Авто"),
("Good image quality", "Хорошее качество изображения"), ("Good image quality", "Хорошее качество изображения"),
("Balanced", "Сбалансированный"), ("Balanced", "Сбалансированный"),
("Optimize reaction time", "Оптимизировать время реакции"), ("Optimize reaction time", "Оптимизировать время реакции"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Pôvodný"), ("Original", "Pôvodný"),
("Shrink", "Zmenšené"), ("Shrink", "Zmenšené"),
("Stretch", "Roztiahnuté"), ("Stretch", "Roztiahnuté"),
("Scrollbar", "Posuvník"),
("ScrollAuto", "Rolovať Auto"),
("Good image quality", "Dobrá kvalita obrazu"), ("Good image quality", "Dobrá kvalita obrazu"),
("Balanced", "Vyvážené"), ("Balanced", "Vyvážené"),
("Optimize reaction time", "Optimalizované pre čas odozvy"), ("Optimize reaction time", "Optimalizované pre čas odozvy"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", ""), ("Original", ""),
("Shrink", ""), ("Shrink", ""),
("Stretch", ""), ("Stretch", ""),
("Scrollbar", ""),
("ScrollAuto", ""),
("Good image quality", ""), ("Good image quality", ""),
("Balanced", ""), ("Balanced", ""),
("Optimize reaction time", ""), ("Optimize reaction time", ""),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Orjinal"), ("Original", "Orjinal"),
("Shrink", "Küçült"), ("Shrink", "Küçült"),
("Stretch", "Uzat"), ("Stretch", "Uzat"),
("Scrollbar", "Kaydırma çubuğu"),
("ScrollAuto", "Otomatik Kaydır"),
("Good image quality", "İyi görüntü kalitesi"), ("Good image quality", "İyi görüntü kalitesi"),
("Balanced", "Dengelenmiş"), ("Balanced", "Dengelenmiş"),
("Optimize reaction time", "Tepki süresini optimize et"), ("Optimize reaction time", "Tepki süresini optimize et"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "原始"), ("Original", "原始"),
("Shrink", "縮減"), ("Shrink", "縮減"),
("Stretch", "延展"), ("Stretch", "延展"),
("Scrollbar", "滾動條"),
("ScrollAuto", "自動滾動"),
("Good image quality", "畫面品質良好"), ("Good image quality", "畫面品質良好"),
("Balanced", "平衡"), ("Balanced", "平衡"),
("Optimize reaction time", "回應速度最佳化"), ("Optimize reaction time", "回應速度最佳化"),

View File

@ -103,6 +103,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Original", "Gốc"), ("Original", "Gốc"),
("Shrink", "Thu nhỏ"), ("Shrink", "Thu nhỏ"),
("Stretch", "Kéo dãn"), ("Stretch", "Kéo dãn"),
("Scrollbar", "Thanh cuộn"),
("ScrollAuto", "Tự động cuộn"),
("Good image quality", "Chất lượng hình ảnh tốt"), ("Good image quality", "Chất lượng hình ảnh tốt"),
("Balanced", "Cân bằng"), ("Balanced", "Cân bằng"),
("Optimize reaction time", "Thời gian phản ứng tối ưu"), ("Optimize reaction time", "Thời gian phản ứng tối ưu"),