diff --git a/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx b/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx
index ff70947ff..6bbc3c4c1 100644
--- a/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx
+++ b/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx
@@ -21,7 +21,15 @@ import {
AsyncLocalizationProvider,
LanguageInfo,
} from '@theia/core/lib/common/i18n/localization';
+import SettingsStepInput from './settings-step-input';
+const maxScale = 200;
+const minScale = -100;
+const scaleStep = 20;
+
+const maxFontSize = 72;
+const minFontSize = 0;
+const fontSizeStep = 2;
export class SettingsComponent extends React.Component<
SettingsComponent.Props,
SettingsComponent.State
@@ -88,6 +96,8 @@ export class SettingsComponent extends React.Component<
}
protected renderSettings(): React.ReactNode {
+ const scalePercentage = 100 + this.state.interfaceScale * 20;
+
return (
{nls.localize(
@@ -160,14 +170,13 @@ export class SettingsComponent extends React.Component<
-
@@ -179,14 +188,13 @@ export class SettingsComponent extends React.Component<
/>
{nls.localize('arduino/preferences/automatic', 'Automatic')}
-
%
@@ -516,13 +524,8 @@ export class SettingsComponent extends React.Component<
}
};
- protected editorFontSizeDidChange = (
- event: React.ChangeEvent
- ): void => {
- const { value } = event.target;
- if (value) {
- this.setState({ editorFontSize: parseInt(value, 10) });
- }
+ private setFontSize = (editorFontSize: number) => {
+ this.setState({ editorFontSize });
};
protected rawAdditionalUrlsValueDidChange = (
@@ -539,18 +542,10 @@ export class SettingsComponent extends React.Component<
this.setState({ autoScaleInterface: event.target.checked });
};
- protected interfaceScaleDidChange = (
- event: React.ChangeEvent
- ): void => {
- const { value } = event.target;
- const percentage = parseInt(value, 10);
- if (isNaN(percentage)) {
- return;
- }
+ private setInterfaceScale = (percentage: number) => {
const interfaceScale = (percentage - 100) / 20;
- if (!isNaN(interfaceScale)) {
- this.setState({ interfaceScale });
- }
+
+ this.setState({ interfaceScale });
};
protected verifyAfterUploadDidChange = (
diff --git a/arduino-ide-extension/src/browser/dialogs/settings/settings-step-input.tsx b/arduino-ide-extension/src/browser/dialogs/settings/settings-step-input.tsx
new file mode 100644
index 000000000..458266fa9
--- /dev/null
+++ b/arduino-ide-extension/src/browser/dialogs/settings/settings-step-input.tsx
@@ -0,0 +1,147 @@
+import * as React from '@theia/core/shared/react';
+import classnames from 'classnames';
+
+interface SettingsStepInputProps {
+ value: number;
+ setSettingsStateValue: (value: number) => void;
+ step: number;
+ maxValue: number;
+ minValue: number;
+ classNames?: { [key: string]: string };
+}
+
+const SettingsStepInput: React.FC = (
+ props: SettingsStepInputProps
+) => {
+ const { value, setSettingsStateValue, step, maxValue, minValue, classNames } =
+ props;
+
+ const [stepUpDisabled, setStepUpDisabled] = React.useState(false);
+ const [stepDownDisabled, setStepDownDisabled] = React.useState(false);
+
+ const onStepUp = (): void => {
+ const valueRoundedToScale = Math.ceil(value / step) * step;
+ const calculatedValue =
+ valueRoundedToScale === value ? value + step : valueRoundedToScale;
+ const newValue = limitValueByCondition(
+ calculatedValue,
+ maxValue,
+ calculatedValue >= maxValue,
+ disableStepUp
+ );
+
+ setSettingsStateValue(newValue);
+ };
+
+ const onStepDown = (): void => {
+ const valueRoundedToScale = Math.floor(value / step) * step;
+ const calculatedValue =
+ valueRoundedToScale === value ? value - step : valueRoundedToScale;
+ const newValue = limitValueByCondition(
+ calculatedValue,
+ minValue,
+ calculatedValue <= minValue,
+ disableStepDown
+ );
+
+ setSettingsStateValue(newValue);
+ };
+
+ const limitValueByCondition = (
+ calculatedValue: number,
+ limitedValue: number,
+ condition: boolean,
+ onConditionTrue: () => void,
+ onConditionFalse = enableButtons
+ ): number => {
+ if (condition) {
+ onConditionTrue();
+ return limitedValue;
+ } else {
+ onConditionFalse();
+ return calculatedValue;
+ }
+ };
+
+ const enableButtons = (): void => {
+ setStepUpDisabled(false);
+ setStepDownDisabled(false);
+ };
+
+ const disableStepUp = (): void => {
+ setStepUpDisabled(true);
+ };
+
+ const disableStepDown = (): void => {
+ setStepDownDisabled(true);
+ };
+
+ const onUserInput = (event: React.ChangeEvent): void => {
+ const { value: eventValue } = event.target;
+
+ if (eventValue === '') {
+ setSettingsStateValue(0);
+ }
+
+ const number = Number(eventValue);
+
+ if (!isNaN(number) && number !== value) {
+ let newValue;
+ if (number > value) {
+ newValue = limitValueByCondition(
+ number,
+ maxValue,
+ number >= maxValue,
+ disableStepUp
+ );
+ } else {
+ newValue = limitValueByCondition(
+ number,
+ minValue,
+ number <= minValue,
+ disableStepDown
+ );
+ }
+
+ setSettingsStateValue(newValue);
+ }
+ };
+
+ // the component does not unmount when we close the settings dialog
+ // in theia which necessitates the below useEffect
+ React.useEffect(() => {
+ if (value > minValue && value < maxValue) {
+ enableButtons();
+ }
+ }, [value, minValue, maxValue]);
+
+ return (
+
+ );
+};
+
+export default SettingsStepInput;
diff --git a/arduino-ide-extension/src/browser/style/index.css b/arduino-ide-extension/src/browser/style/index.css
index fe5d9753f..1a7c98533 100644
--- a/arduino-ide-extension/src/browser/style/index.css
+++ b/arduino-ide-extension/src/browser/style/index.css
@@ -18,6 +18,7 @@
@import './fonts.css';
@import './custom-codicon.css';
@import './progress-bar.css';
+@import './settings-step-input.css';
.theia-input.warning:focus {
outline-width: 1px;
diff --git a/arduino-ide-extension/src/browser/style/settings-step-input.css b/arduino-ide-extension/src/browser/style/settings-step-input.css
new file mode 100644
index 000000000..fd6d6046f
--- /dev/null
+++ b/arduino-ide-extension/src/browser/style/settings-step-input.css
@@ -0,0 +1,47 @@
+.settings-step-input-container {
+ position: relative
+}
+
+.settings-step-input-element::-webkit-inner-spin-button,
+.settings-step-input-element::-webkit-outer-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+
+.settings-step-input-buttons-container {
+ display: none;
+ flex-direction: column;
+ position: absolute;
+ right: 0px;
+ top: 50%;
+ transform: translate(0px, -50%);
+ height: calc(100% - 4px);
+ width: 14px;
+ padding: 2px;
+ background: white;
+}
+
+.settings-step-input-container:hover > .settings-step-input-buttons-container {
+ display: flex;
+}
+
+.settings-step-input-up-button {
+ transform: rotate(-180deg);
+}
+
+.settings-step-input-button {
+ border: none;
+ border-radius: 0;
+ height: 50%;
+ width: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ user-select: none;
+ cursor: pointer;
+ line-height: 12px;
+}
+
+.settings-step-input-button:hover {
+ background: rgba(128, 128, 128, 0.8);
+}