diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 30b227d0415..3c42afa59aa 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,14 +1,29 @@
---
name: Bug report
-about: Omega is not working like it should? Let us know!
+about: Upsilon is not working like it should? Let us know!
title: ''
-labels: Bug, Triage
+labels: 'Status: Triage, Type: Bug'
assignees: ''
---
-#### Describe the bug
+**Describe the bug**
+A clear and concise description of what the bug is.
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
-#### Environment
- - Omega Version: {go to settings > about > Omega Version and type the version here}
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Device (please complete the following information):**
+ - The device on which you're running Upsilon (computer, n0110, n0100, etc...)
+ - Upsilon Version: [go to settings > about > Upsilon Version and type the version here]
+ - Upsilon commit: [settings > about > click one time on epsilon version]
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
deleted file mode 100644
index 3ba13e0cec6..00000000000
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ /dev/null
@@ -1 +0,0 @@
-blank_issues_enabled: false
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index eee03aa6ac5..340a7684f13 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,10 +1,17 @@
---
name: Feature request
-about: Suggest an idea for an improvement of Omega
+about: Suggest an idea for Upsilon
title: ''
-labels: Feature, Triage
+labels: 'Status: Triage, Type: Feature'
assignees: ''
---
-#### What I want to see in the next version of Omega
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md
index 38b47c71fbd..30134e27332 100644
--- a/.github/ISSUE_TEMPLATE/other.md
+++ b/.github/ISSUE_TEMPLATE/other.md
@@ -1,8 +1,8 @@
---
name: Other
-about: A question? A problem? ...
+about: A question? A problem? …
title: ''
-labels: Triage
+labels: 'Status: Triage'
assignees: ''
---
diff --git a/.github/ISSUE_TEMPLATE/problems-during-installation.md b/.github/ISSUE_TEMPLATE/problems-during-installation.md
index 347b6d9574a..329de3b67af 100644
--- a/.github/ISSUE_TEMPLATE/problems-during-installation.md
+++ b/.github/ISSUE_TEMPLATE/problems-during-installation.md
@@ -1,19 +1,19 @@
---
name: Problems during installation
-about: Need help to install Omega?
+about: Need help to install Upsilon?
title: ''
-labels: Installation issue, Triage
+labels: 'Status: Triage, Type: Installation issue'
assignees: ''
---
-#### Describe the problem
+**Describe the problem**
-#### Logs
+**Logs**
```
Copy/paste the logs here (If you have some)
```
-#### Environment
- - Omega Version: {go to settings > about > Omega Version and type the version here}
+**Environment**
+ - Upsilon Version: {go to settings > about > Upsilon Version and type the version here}
diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml
index 7f8c4832175..e2fd55ddd37 100644
--- a/.github/workflows/ci-workflow.yml
+++ b/.github/workflows/ci-workflow.yml
@@ -8,31 +8,90 @@ on:
triggerIos:
description: 'Run iOS tests'
required: true
- default: 'no'
+ default: 'yes'
triggerMacos:
description: 'Run macOS tests'
required: true
- default: 'no'
+ default: 'yes'
trigger3DS:
description: 'Run 3DS tests'
required: true
- default: 'no'
-
+ default: 'yes'
jobs:
+ fxcg:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ submodules: 'recursive'
+ - name: Install dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install curl git python3 build-essential cmake pkg-config -y
+ - name: Get latest gint commit hash
+ run: |
+ LATEST_COMMIT_HASH=$(curl --silent https://gitea.planet-casio.com/api/v1/repos/Lephenixnoir/gint/branches/master | jq -r .commit.id)
+ echo "Latest commit hash is: $LATEST_COMMIT_HASH"
+ echo "LATEST_COMMIT_HASH=$LATEST_COMMIT_HASH" >> $GITHUB_OUTPUT
+ id: get-latest-commit-hash
+ - name: Cache gint/fxsdk installation
+ id: cache-gint
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/.local/*/*
+ !~/.local/share/containers
+ key: ${{ runner.os }}-gint-${{ steps.get-latest-commit-hash.outputs.LATEST_COMMIT_HASH }}
+ - name: Install gint/fxsdk
+ if: steps.cache-gint.outputs.cache-hit != 'true'
+ env:
+ URL: "https://gitea.planet-casio.com/Lephenixnoir/GiteaPC/archive/master.tar.gz"
+ run: |
+ export PATH="~/.local/bin:$PATH"
+ cd "$(mktemp -d)"
+ curl "$URL" -o giteapc-master.tar.gz
+ tar -xzf giteapc-master.tar.gz
+ cd giteapc
+ python3 giteapc.py install Lephenixnoir/GiteaPC -y
+ sudo apt-get install python3-pil libusb-1.0-0-dev libudev-dev libsdl2-dev libpng-dev libudisks2-dev libglib2.0-dev libmpfr-dev libmpc-dev libppl-dev -y
+ giteapc install Lephenixnoir/fxsdk:noudisks2 Lephenixnoir/sh-elf-binutils Lephenixnoir/sh-elf-gcc -y
+ giteapc install Lephenixnoir/OpenLibm Vhex-Kernel-Core/fxlibc Lephenixnoir/sh-elf-gcc -y
+ giteapc install Lephenixnoir/gint -y
+ - name: Add fxsdk to PATH
+ run: echo "~/.local/bin" >> $GITHUB_PATH
+ - run: make -j2 PLATFORM=simulator TARGET=fxcg
+ - id: 'auth'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/auth@v0'
+ with:
+ credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}'
+ - id: 'upload-directory'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/upload-cloud-storage@v0'
+ with:
+ path: 'output/release/simulator/fxcg/epsilon.g3a'
+ destination: 'upsilon-binfiles.appspot.com/dev/simulator/'
+ parent: false
+ - uses: actions/upload-artifact@master
+ with:
+ name: epsilon.g3a
+ path: output/release/simulator/fxcg/epsilon.g3a
nintendo_3ds:
- if: github.event.inputs.trigger3DS == 'yes'
+ if: github.event.inputs.trigger3DS == 'yes' || github.event.inputs.trigger3DS == ''
runs-on: ubuntu-latest
+ container: devkitpro/devkitarm:latest
steps:
- - run: wget https://github.com/devkitPro/pacman/releases/download/v1.0.2/devkitpro-pacman.amd64.deb -O /tmp/devkitpro-pacman.deb
- - run: yes | sudo dpkg -i /tmp/devkitpro-pacman.deb
- - run: yes | sudo dkp-pacman -Syu --needed devkitARM 3dstools libctru
- - run: echo ::set-env name=DEVKITPRO::/opt/devkitpro
- - run: echo ::set-env name=DEVKITARM::/opt/devkitpro/devkitARM
- - run: echo ::set-env name=PATH::$DEVKITPRO/tools/bin:$DEVKITARM/bin:$PATH
-
- uses: actions/checkout@v1
with:
submodules: true
+ - run: sudo apt-get update
+ - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config -y
+ - run: yes | sudo dkp-pacman -S --needed devkitARM 3dstools libctru
+ - run: wget https://github.com/3DSGuy/Project_CTR/releases/download/makerom-v0.18.3/makerom-v0.18.3-ubuntu_x86_64.zip
+ - run: unzip makerom-v0.18.3-ubuntu_x86_64.zip
+ - run: rm makerom-v0.18.3-ubuntu_x86_64.zip
+ - run: chmod +x ./makerom
+ - run: echo "PATH=.:$PATH" >> $GITHUB_ENV
- run: make -j2 PLATFORM=simulator TARGET=3ds
- run: make -j2 PLATFORM=simulator TARGET=3ds epsilon.cia
- uses: actions/upload-artifact@master
@@ -49,7 +108,21 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- - run: make -j2 PLATFORM=simulator TARGET=android
+ - run: wget -nv https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip
+ - run: unzip -q android-ndk-r21e-linux-x86_64.zip
+ - run: make -j2 PLATFORM=simulator TARGET=android NDK_PATH=./android-ndk-r21e
+ - id: 'auth'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/auth@v0'
+ with:
+ credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}'
+ - id: 'upload-file'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/upload-cloud-storage@v0'
+ with:
+ path: 'output/release/simulator/android/epsilon.apk'
+ destination: 'upsilon-binfiles.appspot.com/dev/simulator/'
+ parent: false
- uses: actions/upload-artifact@master
with:
name: epsilon-android.apk
@@ -91,6 +164,18 @@ jobs:
- run: mv output/release/device/n0100/flasher.light.bin final-output/flasher.light.bin
- run: find final-output/ -type f -exec bash -c "shasum -a 256 -b {} > {}.sha256" \;
- run: tar cvfz binpack-n0100.tgz final-output/*
+ - id: 'auth'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon'}}
+ uses: 'google-github-actions/auth@v0'
+ with:
+ credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}'
+ - id: 'upload-directory'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon'}}
+ uses: 'google-github-actions/upload-cloud-storage@v0'
+ with:
+ path: 'final-output/'
+ destination: 'upsilon-binfiles.appspot.com/dev/n100/'
+ parent: false
- uses: actions/upload-artifact@master
with:
name: epsilon-binpack-n0100.tgz
@@ -103,16 +188,29 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- - run: make -j2 epsilon.dfu
- - run: make -j2 epsilon.onboarding.dfu
- - run: make -j2 epsilon.onboarding.update.dfu
- - run: make -j2 epsilon.onboarding.beta.dfu
- - run: make -j2 flasher.light.dfu
- - run: make -j2 flasher.verbose.dfu
- - run: make -j2 bench.ram.dfu
- - run: make -j2 bench.flash.dfu
- - run: make -j2 binpack
+ - run: make -j2 MODEL=n0110 epsilon.dfu
+ - run: make -j2 MODEL=n0110 epsilon.onboarding.dfu
+ - run: make -j2 MODEL=n0110 epsilon.onboarding.update.dfu
+ - run: make -j2 MODEL=n0110 epsilon.onboarding.beta.dfu
+ - run: make -j2 MODEL=n0110 flasher.light.dfu
+ - run: make -j2 MODEL=n0110 flasher.verbose.dfu
+ # We don't need bench as it is used only in factory
+ # - run: make -j2 bench.ram.dfu
+ # - run: make -j2 bench.flash.dfu
+ - run: make -j2 MODEL=n0110 binpack
- run: cp output/release/device/n0110/binpack-n0110-`git rev-parse HEAD | head -c 7`.tgz output/release/device/n0110/binpack-n0110.tgz
+ - id: 'auth'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/auth@v0'
+ with:
+ credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}'
+ - id: 'upload-directory'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/upload-cloud-storage@v0'
+ with:
+ path: 'output/release/device/n0110/binpack/'
+ destination: 'upsilon-binfiles.appspot.com/dev/n110/'
+ parent: false
- uses: actions/upload-artifact@master
with:
name: epsilon-binpack-n0110.tgz
@@ -121,17 +219,36 @@ jobs:
runs-on: ubuntu-latest
steps:
- run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
- - uses: numworks/setup-arm-toolchain@2020-q2
+ - uses: numworks/setup-arm-toolchain@2022-08
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- - run: make -j2 bootloader.dfu
- - run: make MODEL=bootloader -j2 epsilon.A.dfu epsilon.B.dfu
- - run: make MODEL=bootloader -j2 epsilon.onboarding.A.dfu epsilon.onboarding.B.dfu
- - run: make MODEL=bootloader -j2 epsilon.onboarding.update.A.dfu epsilon.onboarding.update.B.dfu
- - run: make MODEL=bootloader -j2 epsilon.onboarding.beta.A.dfu epsilon.onboarding.beta.B.dfu
+ - run: make -j2 MODEL=n0110 bootloader
+ - run: make -j2 epsilon.A.dfu epsilon.B.dfu
+ - run: make -j2 epsilon.onboarding.A.dfu
+ - run: make -j2 epsilon.onboarding.B.dfu
+ - run: make -j2 epsilon.onboarding.update.A.dfu
+ - run: make -j2 epsilon.onboarding.update.B.dfu
+ - run: make -j2 epsilon.onboarding.beta.A.dfu
+ - run: make -j2 epsilon.onboarding.beta.B.dfu
- run: make -j2 binpack
- run: cp output/release/device/bootloader/binpack-bootloader-`git rev-parse HEAD | head -c 7`.tgz output/release/device/bootloader/binpack-bootloader.tgz
+ - run: cp output/release/device/n0110/bootloader.bin output/release/device/bootloader/binpack/
+ - run: cp output/release/device/n0110/bootloader.bin output/release/device/bootloader/
+ - run: cd output/release/device/bootloader && for binary in *.bin; do shasum -a 256 -b binpack/${binary} > binpack/${binary}.sha256;done
+ - run: cd output/release/device/bootloader && tar cvfz binpack-bootloader.tgz binpack/*
+ - id: 'auth'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/auth@v0'
+ with:
+ credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}'
+ - id: 'upload-directory'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/upload-cloud-storage@v0'
+ with:
+ path: 'output/release/device/bootloader/binpack/'
+ destination: 'upsilon-binfiles.appspot.com/dev/n110/'
+ parent: false
- uses: actions/upload-artifact@master
with:
name: epsilon-binpack-bootloader.tgz
@@ -150,6 +267,18 @@ jobs:
- run: make -j2 PLATFORM=simulator
- run: make -j2 PLATFORM=simulator test.exe
- run: cmd /c output\release\simulator\windows\test.exe --headless
+ - id: 'auth'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/auth@v0'
+ with:
+ credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}'
+ - id: 'upload-file'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/upload-cloud-storage@v0'
+ with:
+ path: 'output/release/simulator/windows/epsilon.exe'
+ destination: 'upsilon-binfiles.appspot.com/dev/simulator/'
+ parent: false
- uses: actions/upload-artifact@master
with:
name: epsilon-windows.exe
@@ -157,15 +286,27 @@ jobs:
web:
runs-on: ubuntu-latest
steps:
- - uses: numworks/setup-emscripten@v1
+ - uses: numworks/setup-emscripten@master
with:
- sdk: latest-upstream
+ sdk: latest
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- run: make -j2 PLATFORM=simulator TARGET=web
- run: make -j2 PLATFORM=simulator TARGET=web test.js
- run: node output/release/simulator/web/test.js --headless
+ - id: 'auth'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/auth@v0'
+ with:
+ credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}'
+ - id: 'upload-file'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/upload-cloud-storage@v0'
+ with:
+ path: 'output/release/simulator/web/epsilon.js'
+ destination: 'upsilon-binfiles.appspot.com/dev/simulator/'
+ parent: false
- uses: actions/upload-artifact@master
with:
name: epsilon-web.zip
@@ -180,12 +321,24 @@ jobs:
- run: make -j2 PLATFORM=simulator
- run: make -j2 PLATFORM=simulator test.bin
- run: output/release/simulator/linux/test.bin --headless
+ - id: 'auth'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/auth@v0'
+ with:
+ credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}'
+ - id: 'upload-file'
+ if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }}
+ uses: 'google-github-actions/upload-cloud-storage@v0'
+ with:
+ path: 'output/release/simulator/linux/epsilon.bin'
+ destination: 'upsilon-binfiles.appspot.com/dev/simulator/'
+ parent: false
- uses: actions/upload-artifact@master
with:
name: epsilon-linux.bin
path: output/release/simulator/linux/epsilon.bin
macos:
- if: github.event.inputs.triggerMacos == 'yes'
+ if: github.event.inputs.triggerMacos == 'yes' || github.event.inputs.triggerMacos == ''
runs-on: macOS-latest
steps:
- run: brew install numworks/tap/epsilon-sdk
@@ -200,7 +353,7 @@ jobs:
name: epsilon-macos.zip
path: output/release/simulator/macos/epsilon.app
ios:
- if: github.event.inputs.triggerIos == 'yes'
+ if: github.event.inputs.triggerIos == 'yes' || github.event.inputs.triggerIos == ''
runs-on: macOS-latest
steps:
- run: brew install numworks/tap/epsilon-sdk
diff --git a/.github/workflows/metric-workflow.yml b/.github/workflows/metric-workflow.yml
index 0cca6ba5360..d7ec925fccf 100644
--- a/.github/workflows/metric-workflow.yml
+++ b/.github/workflows/metric-workflow.yml
@@ -16,7 +16,7 @@ jobs:
ref: ${{ github.event.pull_request.base.sha }}
path: base
- name: Build base
- run: make -j2 -C base epsilon.elf
+ run: make -j2 -C base MODEL=n0110 epsilon.elf
- name: Checkout PR head
uses: actions/checkout@v2
with:
@@ -24,14 +24,13 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
path: head
- name: Build head
- run: make -j2 -C head epsilon.elf
+ run: make -j2 -C head MODEL=n0110 epsilon.elf
- name: Retrieve binary size analysis
id: binary_size
run: echo "::set-output name=table::$(python3 head/build/metrics/binary_size.py base/output/release/device/n0110/epsilon.elf head/output/release/device/n0110/epsilon.elf --labels Base Head --sections .text .rodata .bss .data --custom 'Total (RAM)' .data .bss --custom 'Total (ROM)' .text .rodata .data --escape)"
- name: Add comment
uses: actions/github-script@v3.0.0
with:
- github-token: ${{ secrets.OMEGA_ROBOT_TOKEN }}
script: |
await github.issues.createComment({
owner: context.repo.owner,
diff --git a/.gitignore b/.gitignore
index 8645c08d24b..56cb4179582 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,7 @@ epsilon.map
.vscode
.DS_Store
.gradle
+.idea/
+.vs
+.cache/
+compile_commands.json
diff --git a/.gitmodules b/.gitmodules
index 02641c8d556..a535fa5dadf 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,6 @@
[submodule "apps/rpn"]
path = apps/rpn
- url = https://github.com/Omega-Numworks/Omega-RPN.git
+ url = https://github.com/UpsilonNumworks/Upsilon-RPN.git
[submodule "apps/atomic"]
path = apps/atomic
- url = https://github.com/Omega-Numworks/Omega-Atomic.git
+ url = https://github.com/UpsilonNumworks/atomic
diff --git a/Makefile b/Makefile
index 67f626c9a71..b3705e7f476 100644
--- a/Makefile
+++ b/Makefile
@@ -12,20 +12,40 @@ include build/toolchain.$(TOOLCHAIN).mak
include build/variants.mak
include build/helpers.mk
-ifeq (${MODEL},n0110)
- apps_list = ${EPSILON_APPS}
+ifeq (${MODEL}, n0100)
+ ifeq ($(filter reader,$(apps_list)),)
+ $(warning reader app included, removing it on n0100. )
+ EPSILON_APPS := $(filter-out reader,$(EPSILON_APPS))
+ endif
+ ifneq ($(words $(EPSILON_I18N)), 1)
+ $(warning Only use 1 language on n0100, defaulting to en. )
+ EPSILON_I18N := en
+ endif
+ ifeq ($(INCLUDE_ULAB), 1)
+ $(warning Removing uLab on n0100. )
+ INCLUDE_ULAB := 0
+ endif
+endif
+
+ifeq ($(filter reader,$(apps_list)),)
+ HAS_READER := 1
+endif
+
+# Remove the external apps for the n0100
+ifeq (${MODEL}, n0100)
+ apps_list = $(foreach i, ${EPSILON_APPS}, $(if $(filter external, $(i)),,$(i)))
else
- ifeq (${MODEL},bootloader)
apps_list = ${EPSILON_APPS}
- else
- apps_list = $(foreach i, ${EPSILON_APPS}, $(if $(filter external, $(i)),,$(i)))
- endif
endif
ifdef FORCE_EXTERNAL
apps_list = ${EPSILON_APPS}
endif
+ifeq ($(INCLUDE_ULAB), 1)
+ SFLAGS += -DINCLUDE_ULAB
+endif
+
ifdef HOME_DISPLAY_EXTERNALS
ifneq ($(filter external,$(apps_list)),)
SFLAGS += -DHOME_DISPLAY_EXTERNALS
@@ -73,6 +93,7 @@ help:
@echo " make PLATFORM=simulator TARGET=web"
@echo " make PLATFORM=simulator TARGET=windows"
@echo " make PLATFORM=simulator TARGET=3ds"
+ @echo " make PLATFORM=simulator TARGET=fxcg"
.PHONY: doc
doc:
@@ -86,7 +107,7 @@ print-%:
@echo $*\'s origin is $(origin $*)
# Since we're building out-of-tree, we need to make sure the output directories
-# are created, otherwise the receipes will fail (e.g. gcc will fail to create
+# are created, otherwise the recipes will fail (e.g. gcc will fail to create
# "output/foo/bar.o" because the directory "output/foo" doesn't exist).
# We need to mark those directories as precious, otherwise Make will try to get
# rid of them upon completion (and fail, since those folders won't be empty).
@@ -107,6 +128,7 @@ ifndef USE_LIBA
endif
ifeq ($(USE_LIBA),0)
include liba/Makefile.bridge
+include libaxx/Makefile.bridge
else
SFLAGS += -ffreestanding -nostdinc -nostdlib
include liba/Makefile
@@ -191,3 +213,13 @@ clean_run: cleanandcompile
.PHONY: run
run: compile
${MAKE} start
+
+.PHONY: translations
+translations:
+ @echo "TRANSLATIONS"
+ $(Q) ${PYTHON} build/utilities/translate.py
+
+.PHONY: translations_clean
+translations_clean:
+ @echo "TRANSLATIONS CLEAN"
+ $(Q) ${PYTHON} build/utilities/translations_clean.py
diff --git a/README.fr.md b/README.fr.md
index d7b1093d4b7..5a734af7a63 100644
--- a/README.fr.md
+++ b/README.fr.md
@@ -1,168 +1,474 @@
-
+
-
+
-
+
> Don't understand french ? speak english ? here's the [english README](./README.md) !
## À propos
-Omega est un fork d'Epsilon, l'OS de Numworks tournant sur les calculatrices du même nom, qui apporte beaucoup de fonctionnalités en plus. Omega est fait pour ceux qui aimeraient ajouter certaines fonctionnalités ayant été rejetées par Numworks à leurs calculatrices (pour des raisons 100% compréhensibles !). [Essayez en ligne](https://getomega.web.app/simulator).
+Upsilon est un fork d'Omega, un fork d'Epsilon, l'OS de Numworks tournant sur les calculatrices du même nom, qui apporte beaucoup de fonctionnalités en plus, mais qui fut archivé et fermé pour des raisons légales après un changement de politique de Numworks. Upsilon est fait pour ceux qui aimeraient voir un futur pour les OS créées par les utilisateurs pour Numworks, même après l'arrèt du projet initial.
### Quelques fonctionnalités supplémentaires
-- Retour du calcul littéral
-- Une application RPN
-- Application Externes
-- Des thèmes
-- Python amélioré (module os, méthode open...)
-- Un tableau périodique et toutes les masses molaires des éléments dans la toolbox
-- *Ainsi que d'autres à découvrir...* [Changelogs complets](https://github.com/Omega-Numworks/Omega/wiki/Changelog) | [Fonctionnalités princpales & captures d'écran](https://github.com/Omega-Numworks/Omega/wiki/Main-features).
-## Installation
+- Un module python kandinsky amélioré
+- Un support pour fonds d'écrans personnalisés
+- Des applications externes
+- Un thème Upsilon
+- La surcharge des opérateurs en python
+- Un tableau périodique légèrement amélioré
+- L'utilisation possible du signe "=" dans les calculs
+- *Ainsi que tout ce qui a été ajouté sur Omega, et bien plus...* [Changelogs complets d'Omega](https://github.com/Omega-Numworks/Omega/wiki/Changelog) | [Fonctionnalités principales d'Omega & captures d'écran](https://github.com/Omega-Numworks/Omega/wiki/Main-features).
-### Automatique
+## Installation
-Vous pouvez installer Omega automatiquement depuis [notre site](https://getomega.web.app/) sur la page "installer".
+### Site web
-
+Rendez-vous sur le [site d'Upsilon](https://getupsilon.web.app/) à la section "Installer".
+Si votre calculatrice est reconnue, qu'elle contient une version d'Epsilon inférieure à 16 et que votre navigateur accepte WebUSB, la page vous proposera d'installer Upsilon.
+Ne débranchez votre calculatrice qu'une fois l'installation terminée.
### Manuelle
-Tout d'abord, suivez **la première étape** [ici](https://www.numworks.com/resources/engineering/software/build/), puis :
+ *Vous pouvez vous référer à ce [site internet](https://www.numworks.com/resources/engineering/software/build/)pour la première étape si vous avez des erreurs*
+
+### 1. Installation du SDK
+
+
+
+
+
+1.1 Linux
+
+
+
+
+
+Debian ou Ubuntu
+
+
+
+Il suffit juste d'installer les dépendances en tapant ces commandes dans un Terminal en mode super-utilisateur.
+
+```bash
+apt-get install build-essential git imagemagick libx11-dev libxext-dev libfreetype6-dev libpng-dev libjpeg-dev pkg-config gcc-arm-none-eabi binutils-arm-none-eabi
+```
+
+C'est fait! Vous pouvez aller à l'étape 2.
+
+
+
+
+
+
+
+Fedora
+
+
+
+Installez toutes les dépendances grâce à cette commande:
+
+```bash
+dnf install make automake gcc gcc-c++ kernel-devel git ImageMagick libX11-devel libXext-devel freetype-devel libpng-devel libjpeg-devel pkg-config arm-none-eabi-gcc-cs arm-none-eabi-gcc-cs-c++
+```
+
+
+
+
+
+
+
+Nix/Nixos
+
+
+
+Installez toutes les dépendances grâce à cette commande:
+```bash
+nix-env -p gcc libpng libjpeg xorg.libX11 pkg-config freetype xorg.libXext python3 imagemagick python310Packages.lz4 python310Packages.pypng python310Packages.pypng gcc-arm-embedded
+```
+
+
+
+
+
+
+
+
+
+1.2 Mac
+
+
+
+Il est recommandé d'utiliser [Homebrew](https://brew.sh/). Une fois intsallé, utilisez:
+
+```bash
+brew install numworks/tap/epsilon-sdk
+```
+
+Et toutes les dépendances seront installées.
+
+
+
+Vous pouvez aller à l'étape 2.
+
+
+
+
+
+
+
+1.3 Windows
+
+[Git](http://git-scm.com) doit être installé.
+
+
+
+
+
+Avec Msys2/Mingw (Supportés par Numwoks bien qu'il y ait beaucoup de bugs)
+
+L'environnement de compilation [Msys2](https://www.msys2.org/) est recommandé par Numworks pour obtenir la plupart des outils requis facilement. C'est ici que vous allez copier-colletoutes lecommandes de ce tutoriel. Une fois installé, copier-coller ces deux commandes dans le terminal:
+
+```bash
+pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-freetype mingw-w64-x86_64-pkg-config mingw-w64-x86_64-libusb git make python
+echo "export PATH=/mingw64/bin:$PATH" >> .bashrc
+```
+
+Ensuite, vous devrez installer [GCC toolchain for ARM](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads). Quand il vouest demandde choisir u dossier d'installation, choisissez `C:\msys64\home\User\gcc-arm\`. Il vous faudra ensuite ajouter ce dossier à votre $PATH. Tapez juste:
+
+```bash
+echo "export PATH=$PATH:$HOME/gcc-arm/bin" >> .bashrc
+```
+
+Redémarrez votre terminal et vous pouvez aller à l'étape 2!
+
+
+
+
+
+Avec WSL 2
+
+WSL est un système qui virtualise un environnement GNU/Linux dans Windows.
+
+Votre version de windows doit être >= 1903.
+
+#### Installation de WSL
+
+1. Apuyez simulatanément sur les touches "windows" et "x" puis cliquez sur "Powershell administrateur". Entrez ensuite ceci dans la nouvelle fenêtre:
+
+```powershell
+dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
+```
+
+Cette commande active WSL
+
+```powershell
+dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
+```
+
+Cette commande permet d'autoriser le démarrage des machines signées par Microsoft.
+
+2. Redémarrez votre ordinateur.
+
+3. Téléchargez [ce fichier](https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi) et suivez les instructions d'installation.
+
+4. Ouvrez votre fenêtre powershell comme avant et tapez:
+
+```powershell
+wsl --set-default-version 2
+```
+
+5. téléchargez [Ubuntu](https://www.microsoft.com/store/apps/9n6svws3rx71) depuis le Microsoft store. Vous pouvez aussi installer [Debian](https://www.microsoft.com/store/productI9MSVKQC78PK6).
+
+WSL est maintenant installé.
+
+6. Installez maintenant la version pour ARM de GCC.
+```bash
+sudo apt-get install build-essential git imagemagick libx11-dev libxext-dev libfreetype6-dev libpng-dev libjpeg-dev pkg-config gcc-arm-none-eabi binutils-arm-none-eabi
+```
+
+### Installation d'usbipd pour connecter la calculatrice à WSL (facultatif)
+
+Pour connecter la calculatrice, il faut installer cet [outil](https://github.com/dorssel/usbipd-win/releases/download/v1.3.0/usbipd-win_1.3.0.msi). Il permet de connecter des périphériques par internet. Suivez les instructions pour installer.
+
+#### Ubuntu
+
+1. Dans un terminal WSL Ubuntu, tapez:
+
+```bash
+sudo apt install linux-tools-5.4.0-77-generic hwdata
+```
+
+2. Editez /etc/sudoers pour que l'on puisse utiliser la commande usbip. Sur Ubutu, cele est fait de cette manière:
+
+```bash
+sudo visudo
+```
+
+3. Ajoutez `/usr/lib/linux-tools/5.4.0-77-generic` au début du secure_path. Après édition, la ligne devrait ressembler à:
+`Defaults secure_path="/usr/lib/linux-tools/5.4.0-77-generic:/usr/local/sbin:..."`
+
+#### Debian
+
+1.Si vous utiliser Debian, utilisez cette commande:
+
+```bash
+sudo apt install usbip hwdata usbutils
+```
+
+### Pour connecter la calculatrice à WSL
+
+1. Ouvrez encore un powershell en mode administrateur et tapez:
+
+```powershell
+ usbipd wsl list
+```
+
+Ceci va lister les périphériques USB connectés à l'ordinateur. Reagrdez le BUSID de votre "Numworks Calculator".
+
+2. Maintenant, lancez cette commande en remplçant par celui de votre caculatrice:
+
+```powershell
+usbipd wsl attach --busid
+```
+
+Le mot de passe de votre machine WSL vous sera demandé.
+
+Vous pouvez aller à l'étape 2.
+
+
+
+
+
+
+
+### 2. Récupérer le code source
+
+Le code source est disponible dans une repository git. Récupérez-le de cette manière:
+
+```bash
+git clone --recursive https://github.com/UpsilonNumworks/Upsilon.git
+cd Upsilon
+git checkout upsilon-dev
+```
+
+
+
+### 3. Choisissez le système à compiler
- Modèle n0100
-(note : vous pouvez changer `EPSILON_I18N=fr` en `en`, `nl`, `pt`, `it`, `de`, `es` ou `hu`).
+Model n0100
+
+(note: vous pouvez changer l'argument `EPSILON_I18N=en` avec `fr`, `nl`, `pt`, `it`, `de`, `es` or `hu`).
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout omega-master
make MODEL=n0100 clean
-make MODEL=n0100 EPSILON_I18N=fr OMEGA_USERNAME="{Votre nom ici, 15 caractères max}" -j4
+make MODEL=n0100 EPSILON_I18N=en OMEGA_USERNAME="{Votre nom, maximum 15 caractères}" -j4
+```
+
+Maintenant, lancez soit:
+
+```bash
make MODEL=n0100 epsilon_flash
```
-Important : N'oubliez pas l'argument `--recursive`, Omega a besoin de sous-modules.
-Vous pouvez aussi changer le nombre de processus parallèles pendant la compilation en changeant la valeur suivant `-j`.
+pour directement flasher la calculatrice après avoir appuyé simultanément sur `reset` et `6` et avoir branché la calculatrice à l'ordinateur.
+
+
+
+soit:
+
+```bash
+make MODEL=n0100 OMEGA_USERNAME="" binpack -j4
+```
+
+pour compiler les binpacks que vous pouvez distribuer et flasher depuis le [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0100/).
- Modèle n0110
+
+Model n0110
+
+Le bootloader vous permet d'installer firmware dans des "slots" séparés. Dans ce cas les applications externes ne pourront pas utiliser toute la mémoire mais la moitié. Si un seul slot est utilisé, le bootloader permettra d'utiliser toute la mémoire. Sans bootloader, les apps external peuvent utiliser toute la mémoire.
+
+
+Bootloader
+
+Votre calculatrice doit être flashé avec le bootloader d'[Upsilon](https://getupsilon.web.app) ou d'[Omega](https://getomega.dev).
+Compilez avec:
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout omega-master
make clean
-make OMEGA_USERNAME="{Votre nom ici, 15 caractères max}" -j4
-make epsilon_flash
+make OMEGA_USERNAME="{Votre nom, max 15 caractères}" -j4
+```
+
+Ensuite lancez soit:
+
+```bash
+make epsilon.A_flash
+```
+
+pour flasher le slot actuel ou pour flasher par le flasher du booloader avec RESET, puis 4 (flash) et 1 (flash slots) pour flasher n'importe quel slot.
+
+
+
+soit:
+
+```bash
+make OMEGA_USERNAME="{Votre nom, max 15 caractères}" binpack -j4
+```
+
+pour compiler les binpacks que vous pouvez distribuer et flasher depuis le [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0100/). Vous les trouverez dans `output/release/device/bootloader/`.
+
+
+
+
+
+Model n0110 sans bootloader (obsolète, utilisez le bootloader à la place pour la protection contre Epsilon)
+Compilez avec:
+
+```bash
+make MODEL=n0110 clean
+make MODEL=n0110 OMEGA_USERNAME="{Votre nom, max 15 caractères}" -j4
+```
+
+Ensuite lancez soit:
+
+```bash
+make MODEL=n0110 epsilon_flash
```
-Important : N'oubliez pas l'argument `--recursive`, Omega a besoin de sous-modules.
-Vous pouvez aussi changer le nombre de processus parallèles pendant la compilation en changeant la valeur suivant `-j`.
+pour directement flasher la calculatrice après avoir appuyé simultanément sur `RESET` et `6` et avoir branché la calculatrice à l'ordinateur.
+
+soit:
+
+```bash
+make MODEL=n0110 OMEGA_USERNAME="{Votre nom, max 15 caractères}" binpack -j4
+```
+
+pour compiler les binpacks que vous pouvez distribuer et flasher depuis le [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0100/). Vous les trouverez dans `output/release/device/n0110/`.
+
+
+
- Fichiers binaires
-
-Ces fichiers peuvent être utilisés pour distribuer Omega (pour que tout le monde puisse le flasher via [Webdfu_Numworks](https://ti-planet.github.io/webdfu_numworks/)).
+Simulateur Natif
+
+Lancez cette commande:
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout omega-master
make clean
-make MODEL=n0100 OMEGA_USERNAME="" -j8
-make MODEL=n0100 OMEGA_USERNAME="" binpack -j8
-make OMEGA_USERNAME="" -j8
-make OMEGA_USERNAME="" binpack -j8
```
+Vous pouvez soit choisir d'utiliser la commmande qui détectera automatiquement votre plateforme:
+```bash
+make PLATFORM=simulator
+```
+Ou choisir une commande qui correspond à votre plateforme:
+```bash
+make PLATFORM=simulator TARGET=android
+make PLATFORM=simulator TARGET=ios
+make PLATFORM=simulator TARGET=macos
+make PLATFORM=simulator TARGET=web
+make PLATFORM=simulator TARGET=windows
+make PLATFORM=simulator TARGET=3ds
+```
+
+Vous trouverez les fichiers du simulateur dans `output/release/simulator/`.
-Important : N'oubliez pas l'argument `--recursive`, Omega a besoin de sous-modules.
-Vous pouvez aussi changer le nombre de processus parallèles pendant la compilation en changeant la valeur suivant `-j`.
-
+
- Simulateur web
-
+
+Simulateur web
+
D'abord, installez emsdk :
```bash
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
-./emsdk install latest-fastcomp
-./emsdk activate latest-fastcomp
+./emsdk install 1.40.1
+./emsdk activate 1.40.1
source emsdk_env.sh
```
-Puis, compilez Omega :
+Puis, compilez Upsilon :
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout omega-master
make clean
-make PLATFORM=simulator TARGET=web OMEGA_USERNAME="{Votre nom ici, 15 caractères max}" -j4
+make PLATFORM=simulator TARGET=web OMEGA_USERNAME="{Votre nom, maximum 15 caractères}" -j4
```
Le simulateur se trouve dans `output/release/simulator/web/simulator.zip`
-Important : N'oubliez pas l'argument `--recursive`, Omega a besoin de sous-modules.
-Vous pouvez aussi changer le nombre de processus parallèles pendant la compilation en changeant la valeur suivant `-j`.
-
- Simulateur 3DS
-
-Vous aurez besoin de devkitPro et de devkitARM disponible dans votre `$PATH` (instructions [ici](https://devkitpro.org/wiki/Getting_Started) (en anglais))
+
+Simulateur pour 3DS
+
+Il vous faut devkitPro et devkitARM installés et dans votre path (les instructions sont [ici](https://devkitpro.org/wiki/Getting_Started))
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout --recursive omega-dev
+git clone --recursive https://github.com/UpsilonNumworks/Upsilon.git
+cd Upsilon
+git checkout --recursive upsilon-dev
make PLATFORM=simulator TARGET=3ds -j
```
-Vous pouvez ensuite copier epsilon.3dsx sur une carte SD pour l'exécuter depuis le HBC ou utiliser 3dslink pour le lancer via le réseau :
+Vous pouvez ensuite mettre epsilon.3dsx sur une carte SDpour le lancer depuis le HBC ou utilisez 3dslink pour le lancer via le réseau:
```bash
-3dslink output/release/simulator/3ds/epsilon.3dsx -a
+3dslink output/release/simulator/3ds/epsilon.3dsx -a <3DS' IP ADDRESS>
```
-Si vous avez besoin d'aide, n'hésitez pas à rejoindre notre serveur discord : https://discord.gg/X2TWhh9
+
-
+Important: n'oubliez pas l'argument `--recursive` Parce qu'Upsilon dépend de submodules.
+Aussi, vous pouvez changer le nombre de processus de compilation en parallèles en changeant le nombre après l'argument `-j`.
+N'oubliez pas de mettre votre nom à la place `{Votre nom, maximum 15 caractères}`.Si vous n'en voulez pas, enlevez l'argument `OMEGA_USERNAME`.
+
+Si vous avez besoin d'aide, n'hésitez pas à rejoindre notre serveur discord :
+
+
---
+## Liens utiles
+
+- [Upsilon external (pour installer des applications supplémentaires et des fonds d'écran)](https://upsilonnumworks.github.io/Upsilon-External/)
+- [Documentation d'ulab](https://micropython-ulab.readthedocs.io/en/latest/)
+
## Contribution
-Pour contribuer, merci de lire le [Wiki](https://github.com/Omega-Numworks/Omega/wiki/Contributing)
+Pour contribuer, merci de lire le [Wiki d'Omega](https://github.com/Omega-Numworks/Omega/wiki/Contributing), les mêmes règles s'appliquent ici.
+
+## Les autres projets
-## Nos autres projets
+Les anciens projets d'Omega, avant sa fermeture, qui ont été utilisés pour ce projet
-* [Omega Themes](https://github.com/Omega-Numworks/Omega-Themes)
-* [Omega Website](https://github.com/Omega-Numworks/Omega-Website)
-* [Omega RPN `APP`](https://github.com/Omega-Numworks/Omega-RPN)
-* [Omega Atomic `APP`](https://github.com/Omega-Numworks/Omega-Atomic)
-* [Omega Design](https://github.com/Omega-Numworks/Omega-Design)
-* [Omega Discord Bot](https://github.com/Omega-Numworks/Omega-Discord-Bot)
-* [Omega App Template `BETA`](https://github.com/Omega-Numworks/Omega-App-Template)
-* [External Apps](https://github.com/Omega-Numworks/External-Apps)
+- [Omega Themes](https://github.com/Omega-Numworks/Omega-Themes)
+- [Omega Website](https://github.com/Omega-Numworks/Omega-Website)
+- [Omega RPN `APP`](https://github.com/Omega-Numworks/Omega-RPN)
+- [Omega Atomic `APP`](https://github.com/Omega-Numworks/Omega-Atomic)
+- [Omega Design](https://github.com/Omega-Numworks/Omega-Design)
+- [Omega Discord Bot](https://github.com/Omega-Numworks/Omega-Discord-Bot)
+- [Omega App Template `BETA`](https://github.com/Omega-Numworks/Omega-App-Template)
+- [External Apps](https://github.com/Omega-Numworks/External-Apps)
## À propos d'Epsilon
+Upsilon est un fork d'Omega, visant a continuer le projet des OS utilisateurs pour Numworks
+
Omega est un fork d'Epsilon, un système d'exploitation performant pour calculatrices graphiques. Il inclut huit applications pour les mathématiques de lycée et d'études supérieurs
Vous pouvez essayer Epsilon depuis votre navigateur sur le [simulateur en ligne](https://www.numworks.com/simulator/).
@@ -173,5 +479,6 @@ NumWorks est une marque déposée de NumWorks SAS, 24 Rue Godot de Mauroy, 75009
Nintendo est Nintendo 3DS sont des marques déposées de Nintendo of America Inc, 4600 150th Ave NE, Redmond, WA 98052, Etats-Unis.
NumWorks SAS et Nintendo of America Inc ne sont en aucun cas associés avec ce projet.
-* NumWorks Epsilon est disponible sous [Lisense CC BY-NC-SA](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
-* Omega est disponible sous [Lisense CC BY-NC-SA](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
+- NumWorks Epsilon est disponible sous [Lisense CC BY-NC-SA](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
+- Omega est disponible sous [Lisense CC BY-NC-SA](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
+- Upsilon est disponible sous [Lisense CC BY-NC-SA](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
diff --git a/README.md b/README.md
index c9b6597d405..f9fbad9f88b 100644
--- a/README.md
+++ b/README.md
@@ -1,137 +1,425 @@
-
+
-
+
-
+
-> Vous ne comprenez pas l'anglais ? vous êtes francophone ? Regardez le [*LISEZ-MOI* français](./README.fr.md) !
+> Vous ne comprenez pas l'anglais ? Vous êtes francophone ? Regardez le [*LISEZ-MOI* français](./README.fr.md) !
## About
-Omega is a fork of Numworks' Epsilon, the OS that runs on their calculator, which brings many features to it. Omega is for the people who want to add features to the calculator, but cannot because they have been rejected by Numworks (for reasons that are 100% understandable!). [Try it online](https://getomega.web.app/simulator).
+Upsilon is a fork of Omega, an user-made OS that runs on the Numworks calculator, which brings many features to it, but was discontinued because of a policy change from Numworks. Upsilon is for the people who want to see a future for user-made OSes for Numworks, even after the closure and archiving of Omega.
### Some new features
-- Adding symbolic calculation back into the calculator
-- An app for RPN
-- Exernal apps
-- A theme engine
-- New python features (os module, open method...)
-- A periodic table app + all of the molar masses for the elements in the toolbox
-- *And much more to discover...* [Complete changelog](https://github.com/Omega-Numworks/Omega/wiki/Changelog) | [Main new features + screenshots](https://github.com/Omega-Numworks/Omega/wiki/Main-features).
-## Installation
+- Enhancements for the Kandinsky python module
+- Support for wallpapers
+- External apps
+- A custom theme
+- Operator overload for python
+- Improvements for the Periodic table application
+- *And everything that has been added to Omega before its termination!* [See Omega's changelog here](https://github.com/Omega-Numworks/Omega/wiki/Changelog) | [Main Omega features + screenshots](https://github.com/Omega-Numworks/Omega/wiki/Main-features).
+
+
-### Automatic
+## Installation
-You can install Omega automatically on our website [here](https://getomega.web.app/) in the "install" page.
+### Installer
-
+Go to the [Upsilon website](https://getupsilon.web.app/) to the "Install" section.
+If your calculator is recognized, contains a version of Epsilon lower than 16 and your browser accepts WebUSB, the page will suggest you to install Upsilon.
+Do not disconnect your calculator until the installation is complete.
### Manual
-First of all, follow **step 1** [here](https://www.numworks.com/resources/engineering/software/build/). Then:
+ *You can refer to this [website](https://www.numworks.com/resources/engineering/software/build/) for the first step if you get errors.*
+
+### 1. Install SDK
+
+
+
+
+
+1.1 Linux
+
+
+
+
+
+Debian or Ubuntu
+
+
+
+You just have to install dependencies by running these command with superuser privileges in a Terminal:
+
+```bash
+apt-get install build-essential git imagemagick libx11-dev libxext-dev libfreetype6-dev libpng-dev libjpeg-dev pkg-config gcc-arm-none-eabi binutils-arm-none-eabi
+```
+
+And there you can go to step 2!
+
+
+
+
+
+
+
+Fedora
+
+
+
+To install all dependencies:
+
+```bash
+dnf install make automake gcc gcc-c++ kernel-devel git ImageMagick libX11-devel libXext-devel freetype-devel libpng-devel libjpeg-devel pkg-config arm-none-eabi-gcc-cs arm-none-eabi-gcc-cs-c++
+```
+
+
+
+
- Model n0100
+
+Nix or Nixos
+
+
+
+To install all dependencies:
+
+```bash
+nix-shell -p gcc libpng libjpeg xorg.libX11 pkg-config freetype xorg.libXext python3 imagemagick python310Packages.lz4 python310Packages.pypng python310Packages.pypng gcc-arm-embedded
+```
+
+
+
+
+
+
+
+
+
+
+
+1.2 Mac
+
+
+
+It's recommended to use [Homebrew](https://brew.sh/). Once it's installed, just run:
+
+```bash
+brew install numworks/tap/epsilon-sdk
+```
+
+and it will install all dependencies.
+
+
+
+And there you can go to step 2!
+
+
+
+
+
+
+
+1.3 Windows
+
+
+
+
+
+With Msys2/Mingw (officialized by numworks but with a lot of bugs)
+
+[Msys2](https://www.msys2.org/) environment is recommended by Numworks to get most of the required tools on Windows easily. It's where you'll paste all the commands of this tutorial. Once it'sinstalled, paste these commands into the Msys2 terminal.
+
+```bash
+pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-freetype mingw-w64-x86_64-pkg-config mingw-w64-x86_64-libusb git make python
+echo "export PATH=/mingw64/bin:$PATH" >> .bashrc
+```
+
+Next, you'll need to install the [GCC toolchain for ARM](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads). When prompted for aninstall location, choose `C:\msys64\home\User\gcc-arm\`. You'll then need to add this folder to your $PATH. Just enter:
+
+```bash
+echo "export PATH=$PATH:$HOME/gcc-arm/bin" >> .bashrc
+```
+
+Just restart terminal and you can go to step 2!
+
+
+
+
+
+With WSL 2
+
+You need a windows version >= 1903.
+
+#### WSL Installation
+
+1. Use simultaneously win + X keys and then click on "admin powershell".
+
+```powershell
+dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
+```
+
+This command activate WSL functionalities.
+
+```powershell
+dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
+```
+
+This one allows virtual machines developed by Microsoft.
+
+2. Restart your computer.
+
+3. Download [this file](https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi) and follow instructions.
+
+4. Now open powershell admin like before and type:
+
+```powershell
+wsl --set-default-version 2
+```
+5. Download [Ubuntu](https://www.microsoft.com/store/apps/9n6svws3rx71) from Microsoft store.
+
+WSL is now installed.
+
+6. Then Install GCC cross compiler for ARM.
+```bash
+apt-get install build-essential git imagemagick libx11-dev libxext-dev libfreetype6-dev libpng-dev libjpeg-dev pkg-config gcc-arm-none-eabi binutils-arm-none-eabi
+```
+
+### Usbipd installation to connect your calculator
+If you want to connect to the calculator, you have to connect to install this [tool](https://github.com/dorssel/usbipd-win/releases/download/v1.3.0/usbipd-win_1.3.0.msi). This will allow you toconnect WSL to the calculator through internet. Follow the on screen information to install.
+#### Ubuntu
+1. In a WSL Ubuntu command prompt, type:
+```bash
+sudo apt install linux-tools-5.4.0-77-generic hwdata
+```
+
+2. Edit /etc/sudoers so that root can find the usbip command. On Ubuntu, run this command.
+
+```bash
+sudo visudo
+```
+
+3. Add `/usr/lib/linux-tools/5.4.0-77-generic` to the beginning of secure_path. After editing, the line should look similar to this.
+`Defaults secure_path="/usr/lib/linux-tools/5.4.0-77-generic:/usr/local/sbin:..."`
+
+#### Debian
+
+1. If you use debian for your WSL distro, use this command instead:
+
+```bash
+sudo apt install usbip hwdata usbutils
+```
+
+And that's all for installation and set up.
+
+### To connect your calculator
+
+1. Open an Admin powershell and type:
+
+```powershell
+ usbipd wsl list
+```
+
+This will list your usb devices connected. Look at the BUSID column and remember the one for your calculator (it should be called "Numworks Calculator").
+2. Now run this command replacing `` by your calculator's usb port id:
+
+```powershell
+usbipd wsl attach --busid
+```
+
+It will ask you to type your wsl's password and will connect your calculator to WSL.
+
+You can now go to step 2!
+
+
+
+
+
+
+
+### 2. Set up repo
+
+Clone repo and use 'upsilon-dev' branch by pasting these two commands:
+
+```bash
+git clone --recursive https://github.com/UpsilonNumworks/Upsilon.git
+cd Upsilon
+git checkout upsilon-dev
+```
+
+
+
+### 3. Choose the target
+
+
+
+Model n0100
(note: you can change the `EPSILON_I18N=en` flag to `fr`, `nl`, `pt`, `it`, `de`, `es` or `hu`).
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout omega-master
make MODEL=n0100 clean
-make MODEL=n0100 EPSILON_I18N=en OMEGA_USERNAME="{Your name, max 15 characters}" -j4
+make MODEL=n0100 EPSILON_I18N=en OMEGA_USERNAME="{Your name, max 15 characters}" -j(nproc)
+```
+
+Now, run either:
+
+```bash
make MODEL=n0100 epsilon_flash
```
-Important: Don't forget the `--recursive` tag, because Omega relies on submodules.
-Also, you can change the number of processes that run in parallel during the build by changing the value of the `-j` flag.
-
+to directly flash the calculator after pressing simultaneously `reset` and `6` buttons and plugging in.
+
+
+
+or:
+
+```bash
+make MODEL=n0100 OMEGA_USERNAME="" binpack -j(nproc)
+```
+
+to make binpack which you can flash to the calculator from [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0100/). Binpacks are a great way to share a custom build of Upsilonto friends.
+
- Model n0110
+
+Model n0110
+
+The bootloader allows you to install 2 firmware in separated "slots". If so, external apps won't have all the space but half. Bootloader will allow use of all of the memory if only one slot is flashed. In legacy mode, external apps use all the space available.
+
+
+Bootloader
+
+Your calculator must already have been flashed with [Upsilon](https://getupsilon.web.app)'s or [Omega](https://getomega.dev)'s bootloader.
+Then, build with:
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout omega-master
make clean
-make OMEGA_USERNAME="{Your name, max 15 characters}" -j4
-make epsilon_flash
+make OMEGA_USERNAME="{Your name, max 15 characters}" -j(nproc)
```
-Important: Don't forget the `--recursive` tag, because Omega relies on submodules.
-Also, you can change the number of processes that run in parallel during the build by changing the value of the `-j` flag.
-
+Now, run either:
+
+```bash
+make epsilon.A_flash
+```
+
+to directly flash the calculator into the current slot, or thought bootloader's slot flasher with RESET, then 4 (flash), and 1 (flash slots) for other slots.
+
+
+
+or:
+
+```bash
+make OMEGA_USERNAME="" binpack -j(nproc)
+```
+
+to make binpack which you can flash to the calculator from [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0110/). You'll find them at `output/release/device/bootloader/`. Binpacks are a great way to share a custom build of Upsilon to friends.
+
+
- Bin files
-
-These can be used to distribute Omega (so that it can be flashed by anyone with [Webdfu_Numworks](https://ti-planet.github.io/webdfu_numworks/)).
+Model N0110 legacy (deprecated, use bootloader instead for Epsilon protection)
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout omega-master
+make MODEL=n0110 clean
+make MODEL=n0110 OMEGA_USERNAME="{Your name, max 15 characters}" -j(nproc)
+```
+
+Now, run either:
+
+```bash
+make MODEL=n0110 epsilon_flash
+```
+
+to directly flash the calculator after pressing simultaneously `reset` and `6` buttons and plugging in.
+
+
+
+or:
+
+```bash
+make MODEL=n0110 OMEGA_USERNAME="" binpack -j(nproc)
+```
+
+to make binpack which you can flash to the calculator from [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0110/). You'll find them at `output/release/device/bootloader/`. Binpacks are a great way to share a custom build of Upsilon to friends.
+
+
+
+
+
+
+
+Native simulator
+
+Run this command:
+```bash
make clean
-make MODEL=n0100 OMEGA_USERNAME="" -j8
-make MODEL=n0100 OMEGA_USERNAME="" binpack -j8
-make OMEGA_USERNAME="" -j8
-make OMEGA_USERNAME="" binpack -j8
+```
+You can either build using the following command that will automatically detect your platform:
+```bash
+make PLATFORM=simulator
+```
+or, choose the command corresponding to your platform:
+```bash
+make PLATFORM=simulator TARGET=android
+make PLATFORM=simulator TARGET=ios
+make PLATFORM=simulator TARGET=macos
+make PLATFORM=simulator TARGET=web
+make PLATFORM=simulator TARGET=windows
+make PLATFORM=simulator TARGET=3ds
```
-Important: Don't forget the `--recursive` tag, because Omega relies on submodules.
-Also, you can change the number of processes that run in parallel during the build by changing the value of the `-j` flag.
-
+You'll find simulator files in `output/release/simulator/`.
+
+
- Web simulator
-
+
+Web simulator
+
First, install emsdk :
```bash
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
-./emsdk install latest-fastcomp
-./emsdk activate latest-fastcomp
+./emsdk install 1.40.1
+./emsdk activate 1.40.1
source emsdk_env.sh
```
-Then, compile Omega :
+Then, compile Upsilon :
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout omega-master
make clean
-make PLATFORM=simulator TARGET=web OMEGA_USERNAME="{Your name, max 15 characters}" -j4
+make PLATFORM=simulator TARGET=web OMEGA_USERNAME="{Your name, max 15 characters}" -j$(nproc)
```
The simulator is now in `output/release/simulator/web/simulator.zip`
-Important: Don't forget the `--recursive` tag, because Omega relies on submodules.
-Also, you can change the number of processes that run in parallel during the build by changing the value of the `-j` flag.
-
- 3DS Simulator
-
+
+3DS Simulator
+
You need devkitPro and devkitARM installed and in your path (instructions [here](https://devkitpro.org/wiki/Getting_Started))
```bash
-git clone --recursive https://github.com/Omega-Numworks/Omega.git
-cd Omega
-git checkout --recursive omega-dev
-make PLATFORM=simulator TARGET=3ds -j
+git clone --recursive https://github.com/UpsilonNumworks/Upsilon.git
+cd Upsilon
+git checkout upsilon-dev
+make PLATFORM=simulator TARGET=3ds -j(nproc)
```
+
You can then put epsilon.3dsx on a SD card to run it from the HBC or use 3dslink to launch it over the network:
```bash
@@ -140,28 +428,62 @@ You can then put epsilon.3dsx on a SD card to run it from the HBC or use 3dslink
-If you need help, you can join our Discord server here : https://discord.gg/X2TWhh9
+
+
+
+ Casio fx-CG-series Port
+
+First, install gint and fxsdk along with a cross compiler for the calculator. There are instructions for this (in French, but Google Translate works well enough) [here](https://www.planet-casio.com/Fr/forums/topic16614-last-giteapc-installer-et-mettre-a-jour-automatiquement-des-projets-gitea.html).
+
+Next:
+```bash
+git clone --recursive https://github.com/UpsilonNumworks/Upsilon.git
+cd Omega
+git checkout upsilon-dev
+make PLATFORM=simulator TARGET=fxcg -j$(nproc)
+```
+Then copy the file at `./output/release/simulator/fxcg/epsilon.g3a` to the calculator over USB.
+
+
+
+Important: Don't forget the `--recursive` tag, because Upsilon relies on submodules.
+Also, you can change the number of processes that run in parallel during the build by changing the value of the `-j` flag.
+Don't forget to put your pseudo instead of `{your pseudo, max 15 char}`. If you don't want one, just remove the `OMEGA_USERNAME=""` argument.
+
+
+
+If you need help, you can join our Discord server here :
+
+
-
---
+## Useful links
+
+- [Upsilon external (to install additional apps and wallpapers)](https://upsilonnumworks.github.io/Upsilon-External/)
+- [Ulab documentation](https://micropython-ulab.readthedocs.io/en/latest/)
+
## Contributing
-To contribute, please refer to the [Wiki](https://github.com/Omega-Numworks/Omega/wiki/Contributing)
+To contribute, please refer to [Omega's Wiki](https://github.com/Omega-Numworks/Omega/wiki/Contributing), the same rules apply here.
## Related repositories
-* [Omega Themes](https://github.com/Omega-Numworks/Omega-Themes)
-* [Omega Website](https://github.com/Omega-Numworks/Omega-Website)
-* [Omega RPN `APP`](https://github.com/Omega-Numworks/Omega-RPN)
-* [Omega Atomic `APP`](https://github.com/Omega-Numworks/Omega-Atomic)
-* [Omega Design](https://github.com/Omega-Numworks/Omega-Design)
-* [Omega Discord Bot](https://github.com/Omega-Numworks/Omega-Discord-Bot)
-* [Omega App Template `BETA`](https://github.com/Omega-Numworks/Omega-App-Template)
-* [External Apps](https://github.com/Omega-Numworks/External-Apps)
+Here are the main links toward Omega's different websites and repositories, that have been used for the creation of Upsilon.
+
+- [Omega Themes](https://github.com/Omega-Numworks/Omega-Themes)
+- [Omega Website](https://github.com/Omega-Numworks/Omega-Website)
+- [Omega RPN `APP`](https://github.com/Omega-Numworks/Omega-RPN)
+- [Omega Atomic `APP`](https://github.com/Omega-Numworks/Omega-Atomic)
+- [Omega Design](https://github.com/Omega-Numworks/Omega-Design)
+- [Omega Discord Bot](https://github.com/Omega-Numworks/Omega-Discord-Bot)
+- [Omega App Template `BETA`](https://github.com/Omega-Numworks/Omega-App-Template)
+- [External Apps](https://github.com/Omega-Numworks/External-Apps)
## About Epsilon
+Upsilon is a fork of Omega, after the project's discontinuation.
+
Omega is a fork of Epsilon, a high-performance graphing calculator operating system. It includes eight apps that cover the high school mathematics curriculum.
You can try Epsilon straight from your browser in the [online simulator](https://www.numworks.com/simulator/).
@@ -170,7 +492,9 @@ You can try Epsilon straight from your browser in the [online simulator](https:/
NumWorks is a registered trademark of NumWorks SAS, 24 Rue Godot de Mauroy, 75009 Paris, France.
Nintendo and Nintendo 3DS are registered trademarks of Nintendo of America Inc, 4600 150th Ave NE, Redmond, WA 98052, USA.
-NumWorks SAS and Nintendo of America Inc aren't associated in any shape or form with this project.
+Casio is a registered trademark of Casio Computer Co., Ltd. CORPORATION JAPAN 6-2, Hon-machi 1-chome Shibuya-ku, Tokyo JAPAN 151-8543.
+NumWorks SAS, Nintendo of America Inc and Casio aren't associated in any shape or form with this project.
-* NumWorks Epsilon is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
-* Omega is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
+- NumWorks Epsilon is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
+- Omega is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
+- Upsilon is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).
diff --git a/apps/Makefile b/apps/Makefile
index 820ff690ce3..b2e67a83283 100644
--- a/apps/Makefile
+++ b/apps/Makefile
@@ -23,7 +23,7 @@ ifneq ($(strip $(apps_missing)),)
$(foreach i, $(SUBMODULES_APPS), $(if $(call app_equals, $(filter $(i), $(apps_missing)), $(i)), $(eval miss_modules=1)))
ifeq ($(miss_modules), 1)
- PLS_IGNORE := $(shell >&2 printf "\nSome submodules apps seem to be missing. To download them, assumming you git clone'd the repo, do\n")
+ PLS_IGNORE := $(shell >&2 printf "\nSome submodules apps seem to be missing. To download them, assuming you git clone'd the repo, do\n")
PLS_IGNORE := $(shell >&2 printf " git submodule init\n")
PLS_IGNORE := $(shell >&2 printf " git submodule update\n\n")
endif
@@ -50,6 +50,7 @@ apps_src += $(addprefix apps/,\
exam_mode_configuration_official.cpp:+official \
exam_mode_configuration_non_official.cpp:-official \
global_preferences.cpp \
+ host_filemanager.cpp \
i18n.py \
lock_view.cpp \
main.cpp \
@@ -58,7 +59,9 @@ apps_src += $(addprefix apps/,\
math_variable_box_empty_controller.cpp \
shift_alpha_lock_view.cpp \
suspend_timer.cpp \
+ timer_manager.cpp \
title_bar_view.cpp \
+ xnt_loop.cpp \
)
tests_src += $(addprefix apps/,\
@@ -81,7 +84,7 @@ $(call object_for,apps/apps_container_storage.cpp apps/apps_container.cpp apps/m
country_preferences = apps/country_preferences.csv
language_preferences = apps/language_preferences.csv
-# The header is refered to as so make sure it's findable this way
+# The header is referred to as so make sure it's findable this way
SFLAGS += -I$(BUILD_DIR)
i18n_files += $(addprefix apps/language_,$(addsuffix .universal.i18n, $(EPSILON_I18N)))
@@ -117,6 +120,7 @@ apps_tests_src = $(app_calculation_test_src) $(app_code_test_src) $(app_graph_te
apps_tests_src += $(addprefix apps/,\
alternate_empty_nested_menu_controller.cpp \
global_preferences.cpp \
+ dummy_timer_manager.cpp \
)
ifeq ($(THEME_REPO),local)
diff --git a/apps/apps_container.cpp b/apps/apps_container.cpp
index acf3feb383d..b01c388e204 100644
--- a/apps/apps_container.cpp
+++ b/apps/apps_container.cpp
@@ -29,7 +29,7 @@ AppsContainer::AppsContainer() :
m_globalContext(),
m_variableBoxController(),
m_examPopUpController(this),
- m_promptController(k_promptMessages, k_promptColors, k_promptNumberOfMessages),
+ m_promptController(k_promptMessages, k_promptFGColors, k_promptBGColors, k_promptNumberOfMessages),
m_batteryTimer(),
m_suspendTimer(),
m_backlightDimmingTimer(),
@@ -37,7 +37,8 @@ AppsContainer::AppsContainer() :
m_homeSnapshot(),
m_onBoardingSnapshot(),
m_hardwareTestSnapshot(),
- m_usbConnectedSnapshot()
+ m_usbConnectedSnapshot(),
+ m_startAppSnapshot()
{
m_emptyBatteryWindow.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), false);
// #if __EMSCRIPTEN__
@@ -47,7 +48,7 @@ AppsContainer::AppsContainer() :
* poincareCircuitBreaker is run. This means either whitelisting all Epsilon
* (which makes bigger files to download and slower execution), or
* whitelisting all the symbols (that's a big amount of symbols to find and
- * quite painy to maintain).
+ * quite paint to maintain).
* We just remove the circuit breaker for now.
* TODO: Put the Poincare circuit breaker back on epsilon's web emulator */
@@ -58,6 +59,11 @@ AppsContainer::AppsContainer() :
Poincare::Expression::SetCircuitBreaker(AppsContainer::poincareCircuitBreaker);
// #endif
Ion::Storage::sharedStorage()->setDelegate(this);
+
+ addTimer(&m_batteryTimer);
+ addTimer(&m_suspendTimer);
+ addTimer(&m_backlightDimmingTimer);
+ addTimer(&m_clockTimer);
}
bool AppsContainer::poincareCircuitBreaker() {
@@ -146,8 +152,11 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) {
* We do it before switching to USB application to redraw the battery
* pictogram. */
updateBatteryState();
- if (switchTo(usbConnectedAppSnapshot())) {
- Ion::USB::DFU();
+ if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
+ // If we are in exam mode, we don't switch to usb connected app
+ didProcessEvent = true;
+ } else if (switchTo(usbConnectedAppSnapshot())) {
+ Ion::USB::DFU(true);
// Update LED when exiting DFU mode
Ion::LED::updateColorWithPlugAndCharge();
bool switched = switchTo(activeSnapshot);
@@ -220,6 +229,7 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) {
return didProcessEvent || alphaLockWantsRedraw;
}
+// List of keys that are used to switch between apps, in order of app to go (eg. 0 : First App, 1 : Second App, 2 : Third App, ...)
static constexpr Ion::Events::Event switch_events[] = {
Ion::Events::ShiftSeven, Ion::Events::ShiftEight, Ion::Events::ShiftNine,
Ion::Events::ShiftFour, Ion::Events::ShiftFive, Ion::Events::ShiftSix,
@@ -231,27 +241,33 @@ bool AppsContainer::processEvent(Ion::Events::Event event) {
// Warning: if the window is dirtied, you need to call window()->redraw()
if (event == Ion::Events::USBPlug) {
if (Ion::USB::isPlugged()) {
+ // If the exam mode is enabled, we ask to disable it, else, we enable USB
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
displayExamModePopUp(GlobalPreferences::ExamMode::Off);
window()->redraw();
} else {
Ion::USB::enable();
}
+ // Update brightness when USB is plugged
Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel());
} else {
+ // If the USB isn't plugged in USBPlug event, we disable USB
Ion::USB::disable();
}
return true;
}
+ // If key home or key back is pressed, we switch to the home app.
if (event == Ion::Events::Home || event == Ion::Events::Back) {
switchTo(appSnapshotAtIndex(0));
return true;
}
+ // If shift + Home are pressed, we switch to the first app.
if (event == Ion::Events::ShiftHome) {
switchTo(appSnapshotAtIndex(1));
return true;
}
+ // Iterate through the switch events to find the one that matches the event, if one match, switch to the app at the index of the switch event.
for(int i = 0; i < std::min((int) (sizeof(switch_events) / sizeof(Ion::Events::Event)), APPS_CONTAINER_SNAPSHOT_COUNT); i++) {
if (event == switch_events[i]) {
m_window.redraw(true);
@@ -260,19 +276,44 @@ bool AppsContainer::processEvent(Ion::Events::Event event) {
}
}
+ // Add EE shortcut to go to the settings (app number 12)
+ if (event == Ion::Events::EE) {
+ switchTo(appSnapshotAtIndex(12));
+ return true;
+ }
+
+ // Add Shift + Ans shortcut to go to the previous app
+ if (event == Ion::Events::ShiftAns) {
+ switchTo(appSnapshotAtIndex(m_lastAppIndex));
+ return true;
+ }
+
+ // If the event is the OnOff key, we suspend the calculator.
if (event == Ion::Events::OnOff) {
suspend(true);
return true;
}
+ // If the event is a brightness event, we update the brightness according to the event.
if (event == Ion::Events::BrightnessPlus || event == Ion::Events::BrightnessMinus) {
int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates;
- int direction = (event == Ion::Events::BrightnessPlus) ? Ion::Backlight::NumberOfStepsPerShortcut*delta : -delta*Ion::Backlight::NumberOfStepsPerShortcut;
+ int NumberOfStepsPerShortcut = GlobalPreferences::sharedGlobalPreferences()->brightnessShortcut();
+ int direction = (event == Ion::Events::BrightnessPlus) ? NumberOfStepsPerShortcut*delta : -delta*NumberOfStepsPerShortcut;
GlobalPreferences::sharedGlobalPreferences()->setBrightnessLevel(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()+direction);
}
+ // Else, the event was not processed.
return false;
}
bool AppsContainer::switchTo(App::Snapshot * snapshot) {
+ // Get app index of the snapshot
+ int m_appIndexToSwitch = appIndexFromSnapshot(snapshot);
+ // If the app is home, skip app index saving
+ if (m_appIndexToSwitch != 0) {
+ // Save last app index
+ m_lastAppIndex = m_currentAppIndex;
+ // Save current app index
+ m_currentAppIndex = m_appIndexToSwitch;
+ }
if (s_activeApp && snapshot != s_activeApp->snapshot()) {
resetShiftAlphaStatus();
}
@@ -309,7 +350,13 @@ void AppsContainer::run() {
/* Normal execution. The exception checkpoint must be created before
* switching to the first app, because the first app might create nodes on
* the pool. */
- bool switched = switchTo(initialAppSnapshot());
+ bool switched;
+ if (m_startAppSnapshot != nullptr) {
+ switched = switchTo(m_startAppSnapshot);
+ } else {
+ switched = switchTo(initialAppSnapshot());
+ }
+
assert(switched);
(void) switched; // Silence compilation warning about unused variable.
} else {
@@ -319,7 +366,7 @@ void AppsContainer::run() {
* destroyed from the pool. To avoid using them before packing the app
* (in App::willBecomeInactive for instance), we tidy them early on. */
s_activeApp->snapshot()->tidy();
- /* When an app encoutered an exception due to a full pool, the next time
+ /* When an app encountered an exception due to a full pool, the next time
* the user enters the app, the same exception could happen again which
* would prevent from reopening the app. To avoid being stuck outside the
* app causing the issue, we reset its snapshot when leaving it due to
@@ -353,6 +400,8 @@ bool AppsContainer::updateBatteryState() {
}
void AppsContainer::refreshPreferences() {
+ m_suspendTimer.reset(GlobalPreferences::sharedGlobalPreferences()->idleBeforeSuspendSeconds()*1000/Timer::TickDuration);
+ m_backlightDimmingTimer.reset(GlobalPreferences::sharedGlobalPreferences()->idleBeforeDimmingSeconds()*1000/Timer::TickDuration);
m_window.refreshPreferences();
}
@@ -446,15 +495,6 @@ Window * AppsContainer::window() {
return &m_window;
}
-int AppsContainer::numberOfContainerTimers() {
- return 4;
-}
-
-Timer * AppsContainer::containerTimerAtIndex(int i) {
- Timer * timers[4] = {&m_batteryTimer, &m_suspendTimer, &m_backlightDimmingTimer, &m_clockTimer};
- return timers[i];
-}
-
void AppsContainer::resetShiftAlphaStatus() {
Ion::Events::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default);
updateAlphaLock();
diff --git a/apps/apps_container.h b/apps/apps_container.h
index ab945b6efec..485c5ce3b2d 100644
--- a/apps/apps_container.h
+++ b/apps/apps_container.h
@@ -18,6 +18,7 @@
#include "shared/global_context.h"
#include "clock_timer.h"
#include "on_boarding/prompt_controller.h"
+#include "xnt_loop.h"
#include
@@ -28,6 +29,7 @@ class AppsContainer : public Container, ExamPopUpControllerDelegate, Ion::Storag
static bool poincareCircuitBreaker();
virtual int numberOfApps() = 0;
virtual App::Snapshot * appSnapshotAtIndex(int index) = 0;
+ virtual int appIndexFromSnapshot(App::Snapshot * snapshot) = 0;
App::Snapshot * initialAppSnapshot();
App::Snapshot * hardwareTestAppSnapshot();
App::Snapshot * onBoardingAppSnapshot();
@@ -47,6 +49,8 @@ class AppsContainer : public Container, ExamPopUpControllerDelegate, Ion::Storag
void displayExamModePopUp(GlobalPreferences::ExamMode mode);
void shutdownDueToLowBattery();
void setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus newStatus);
+ CodePoint XNT(CodePoint defaultXNT, bool * shouldRemoveLastCharacter) { return m_XNTLoop.XNT(defaultXNT, shouldRemoveLastCharacter); }
+ void resetXNT() { m_XNTLoop.reset(); }
OnBoarding::PromptController * promptController();
void redrawWindow(bool force = false);
void activateExamMode(GlobalPreferences::ExamMode examMode);
@@ -55,19 +59,23 @@ class AppsContainer : public Container, ExamPopUpControllerDelegate, Ion::Storag
// Ion::StorageDelegate
void storageDidChangeForRecord(const Ion::Storage::Record record) override;
void storageIsFull() override;
+ #ifdef EPSILON_GETOPT
+ void setStartApp(App::Snapshot * snapshot) { m_startAppSnapshot = snapshot; }
+ #endif
protected:
Home::App::Snapshot * homeAppSnapshot() { return &m_homeSnapshot; }
private:
Window * window() override;
- int numberOfContainerTimers() override;
- Timer * containerTimerAtIndex(int i) override;
bool processEvent(Ion::Events::Event event);
void resetShiftAlphaStatus();
bool updateAlphaLock();
static I18n::Message k_promptMessages[];
- static KDColor k_promptColors[];
+ static KDColor k_promptFGColors[];
+ static KDColor k_promptBGColors[];
static int k_promptNumberOfMessages;
+ int m_currentAppIndex; // Home isn't included after the second app switching
+ int m_lastAppIndex;
AppsWindow m_window;
EmptyBatteryWindow m_emptyBatteryWindow;
Shared::GlobalContext m_globalContext;
@@ -83,6 +91,10 @@ class AppsContainer : public Container, ExamPopUpControllerDelegate, Ion::Storag
OnBoarding::App::Snapshot m_onBoardingSnapshot;
HardwareTest::App::Snapshot m_hardwareTestSnapshot;
USB::App::Snapshot m_usbConnectedSnapshot;
+ XNTLoop m_XNTLoop;
+ #ifdef EPSILON_GETOPT
+ App::Snapshot * m_startAppSnapshot;
+ #endif
};
#endif
diff --git a/apps/apps_container_prompt_beta.cpp b/apps/apps_container_prompt_beta.cpp
index 613acc99d9a..729062c6ac5 100644
--- a/apps/apps_container_prompt_beta.cpp
+++ b/apps/apps_container_prompt_beta.cpp
@@ -10,7 +10,7 @@ I18n::Message AppsContainer::k_promptMessages[] = {
I18n::Message::BetaVersionMessage5,
I18n::Message::BetaVersionMessage6};
-KDColor AppsContainer::k_promptColors[] = {
+KDColor AppsContainer::k_promptFGColors[] = {
KDColorBlack,
KDColorBlack,
KDColorBlack,
@@ -20,4 +20,14 @@ KDColor AppsContainer::k_promptColors[] = {
KDColorBlack,
Palette::AccentText};
+KDColor AppsContainer::k_promptBGColors[] = {
+ KDColorWhite,
+ KDColorWhite,
+ KDColorWhite,
+ KDColorWhite,
+ KDColorWhite,
+ KDColorWhite,
+ KDColorWhite,
+ KDColorWhite};
+
int AppsContainer::k_promptNumberOfMessages = 8;
diff --git a/apps/apps_container_prompt_none.cpp b/apps/apps_container_prompt_none.cpp
index 65556d670f8..e750df2b65d 100644
--- a/apps/apps_container_prompt_none.cpp
+++ b/apps/apps_container_prompt_none.cpp
@@ -2,7 +2,8 @@
I18n::Message AppsContainer::k_promptMessages[] = {};
-KDColor AppsContainer::k_promptColors[] = {};
+KDColor AppsContainer::k_promptFGColors[] = {};
+KDColor AppsContainer::k_promptBGColors[] = {};
int AppsContainer::k_promptNumberOfMessages = 0;
diff --git a/apps/apps_container_prompt_update.cpp b/apps/apps_container_prompt_update.cpp
index e837b592f27..59c93f0f478 100644
--- a/apps/apps_container_prompt_update.cpp
+++ b/apps/apps_container_prompt_update.cpp
@@ -8,7 +8,7 @@ I18n::Message AppsContainer::k_promptMessages[] = {
I18n::Message::UpdateMessage3,
I18n::Message::UpdateMessage4};
-KDColor AppsContainer::k_promptColors[] = {
+KDColor AppsContainer::k_promptFGColors[] = {
KDColorBlack,
KDColorBlack,
KDColorBlack,
@@ -16,4 +16,12 @@ KDColor AppsContainer::k_promptColors[] = {
KDColorBlack,
Palette::AccentText};
+KDColor AppsContainer::k_promptBGColors[] = {
+ KDColorWhite,
+ KDColorWhite,
+ KDColorWhite,
+ KDColorBlack,
+ KDColorWhite,
+ KDColorBlack};
+
int AppsContainer::k_promptNumberOfMessages = 6;
diff --git a/apps/apps_container_storage.cpp b/apps/apps_container_storage.cpp
index 2ef60aafa5c..6a945af111e 100644
--- a/apps/apps_container_storage.cpp
+++ b/apps/apps_container_storage.cpp
@@ -34,5 +34,25 @@ App::Snapshot * AppsContainerStorage::appSnapshotAtIndex(int index) {
};
assert(sizeof(snapshots)/sizeof(snapshots[0]) == k_numberOfCommonApps);
assert(index >= 0 && index < k_numberOfCommonApps);
+ // To avoid crashes, we return the home app snapshot if the index is out of
+ // bounds. (no crash in release mode, but an assert in debug mode)
+ if (index >= k_numberOfCommonApps) {
+ return snapshots[0];
+ }
return snapshots[index];
}
+
+// Get the index of the app from its snapshot
+int AppsContainerStorage::appIndexFromSnapshot(App::Snapshot * snapshot) {
+ App::Snapshot * snapshots[] = {
+ homeAppSnapshot()
+ APPS_CONTAINER_SNAPSHOT_LIST
+ };
+ assert(sizeof(snapshots)/sizeof(snapshots[0]) == k_numberOfCommonApps);
+ for (int i = 0; i < k_numberOfCommonApps; i++) {
+ if (snapshots[i] == snapshot) {
+ return i;
+ }
+ }
+ return NULL;
+}
diff --git a/apps/apps_container_storage.h b/apps/apps_container_storage.h
index 9abd3c27ad4..c3191a751da 100644
--- a/apps/apps_container_storage.h
+++ b/apps/apps_container_storage.h
@@ -12,6 +12,7 @@ class AppsContainerStorage : public AppsContainer {
AppsContainerStorage();
int numberOfApps() override;
App::Snapshot * appSnapshotAtIndex(int index) override;
+ int appIndexFromSnapshot(App::Snapshot * snapshot) override;
void * currentAppBuffer() override { return &m_apps; };
private:
union Apps {
diff --git a/apps/atomic b/apps/atomic
index 64f2e38ed1e..5f7063d4474 160000
--- a/apps/atomic
+++ b/apps/atomic
@@ -1 +1 @@
-Subproject commit 64f2e38ed1e4b8a896b0488039fb866b7015ff3f
+Subproject commit 5f7063d447414028a3c4b750cd6dbe83bd6296e6
diff --git a/apps/backlight_dimming_timer.cpp b/apps/backlight_dimming_timer.cpp
index 2f60e809be5..a86c29c0080 100644
--- a/apps/backlight_dimming_timer.cpp
+++ b/apps/backlight_dimming_timer.cpp
@@ -1,11 +1,26 @@
#include "backlight_dimming_timer.h"
+#include "global_preferences.h"
+#include
+#include
+#include
BacklightDimmingTimer::BacklightDimmingTimer() :
- Timer(k_idleBeforeDimmingDuration/Timer::TickDuration)
+ Timer(GlobalPreferences::sharedGlobalPreferences()->idleBeforeDimmingSeconds()*1000/Timer::TickDuration)
{
}
-bool BacklightDimmingTimer::fire() {
- Ion::Backlight::setBrightness(k_dimBacklightBrightness);
+bool BacklightDimmingTimer::fire(){
+ int i = Ion::Backlight::brightness();
+ while (i > 0){
+ int t = 20;
+ Ion::Events::Event e = Ion::Events::getEvent(&t);
+ AppsContainer::sharedAppsContainer()->dispatchEvent(e);
+ if (e.isKeyboardEvent()){
+ return false;
+ }
+
+ Ion::Backlight::setBrightness(i);
+ i -= 15;
+ }
return false;
}
diff --git a/apps/backlight_dimming_timer.h b/apps/backlight_dimming_timer.h
index 17059e408de..1925913705d 100644
--- a/apps/backlight_dimming_timer.h
+++ b/apps/backlight_dimming_timer.h
@@ -7,8 +7,6 @@ class BacklightDimmingTimer : public Timer {
public:
BacklightDimmingTimer();
private:
- constexpr static int k_idleBeforeDimmingDuration = 30*1000; // In miliseconds
- constexpr static int k_dimBacklightBrightness = 0;
bool fire() override;
};
diff --git a/apps/battery_view.cpp b/apps/battery_view.cpp
index 28ab8d9794e..c70413b9f98 100644
--- a/apps/battery_view.cpp
+++ b/apps/battery_view.cpp
@@ -60,32 +60,36 @@ void BatteryView::drawRect(KDContext * ctx, KDRect rect) const {
*'content' depends on the charge */
// Draw the left part
- ctx->fillRect(KDRect(0, 0, k_elementWidth, k_batteryHeight), Palette::Battery);
+ ctx->fillRect(KDRect(0, 1, k_elementWidth, k_batteryHeight - 2), Palette::Battery);
+
+ // Draw top and bottom part
+ ctx->fillRect(KDRect(1, 0, k_batteryWidth-3, 1), Palette::Battery);
+ ctx->fillRect(KDRect(1, k_batteryHeight-1, k_batteryWidth-3, 1), Palette::Battery);
// Draw the middle part
constexpr KDCoordinate batteryInsideX = k_elementWidth+k_separatorThickness;
constexpr KDCoordinate batteryInsideWidth = k_batteryWidth-3*k_elementWidth-2*k_separatorThickness;
if (m_isCharging) {
// Charging: Yellow background with flash
- ctx->fillRect(KDRect(batteryInsideX, 0, batteryInsideWidth, k_batteryHeight), Palette::BatteryInCharge);
+ ctx->fillRect(KDRect(batteryInsideX, 2, batteryInsideWidth, k_batteryHeight-4), Palette::BatteryInCharge);
KDRect frame((k_batteryWidth-k_flashWidth)/2, 0, k_flashWidth, k_flashHeight);
KDColor flashWorkingBuffer[BatteryView::k_flashHeight*BatteryView::k_flashWidth];
ctx->blendRectWithMask(frame, Palette::Battery, (const uint8_t *)flashMask, flashWorkingBuffer);
} else if (m_chargeState == Ion::Battery::Charge::LOW) {
assert(!m_isPlugged);
// Low: Quite empty battery
- ctx->fillRect(KDRect(batteryInsideX, 0, 2*k_elementWidth, k_batteryHeight), Palette::BatteryLow);
- ctx->fillRect(KDRect(3*k_elementWidth+k_separatorThickness, 0, k_batteryWidth-5*k_elementWidth-2*k_separatorThickness, k_batteryHeight), Palette::BatteryInCharge);
+ ctx->fillRect(KDRect(batteryInsideX, 2, 2*k_elementWidth, k_batteryHeight-4), Palette::BatteryLow);
+ ctx->fillRect(KDRect(3*k_elementWidth+k_separatorThickness, 2, k_batteryWidth-5*k_elementWidth-2*k_separatorThickness, k_batteryHeight-4), KDColor::blend(Palette::Toolbar, Palette::Battery, 128));
} else if (m_chargeState == Ion::Battery::Charge::SOMEWHERE_INBETWEEN) {
assert(!m_isPlugged);
// Middle: Half full battery
constexpr KDCoordinate middleChargeWidth = batteryInsideWidth/2;
- ctx->fillRect(KDRect(batteryInsideX, 0, middleChargeWidth, k_batteryHeight), Palette::Battery);
- ctx->fillRect(KDRect(batteryInsideX+middleChargeWidth, 0, middleChargeWidth, k_batteryHeight), Palette::BatteryInCharge);
+ ctx->fillRect(KDRect(batteryInsideX, 2, middleChargeWidth, k_batteryHeight-4), Palette::Battery);
+ ctx->fillRect(KDRect(batteryInsideX+middleChargeWidth, 2, middleChargeWidth+1, k_batteryHeight-4), KDColor::blend(Palette::Toolbar, Palette::Battery, 128));
} else {
assert(m_chargeState == Ion::Battery::Charge::FULL);
// Full but not plugged: Full battery
- ctx->fillRect(KDRect(batteryInsideX, 0, batteryInsideWidth, k_batteryHeight), Palette::Battery);
+ ctx->fillRect(KDRect(batteryInsideX, 2, batteryInsideWidth, k_batteryHeight-4), Palette::Battery);
if (m_isPlugged) {
// Plugged and full: Full battery with tick
KDRect frame((k_batteryWidth-k_tickWidth)/2, (k_batteryHeight-k_tickHeight)/2, k_tickWidth, k_tickHeight);
@@ -95,7 +99,7 @@ void BatteryView::drawRect(KDContext * ctx, KDRect rect) const {
}
// Draw the right part
- ctx->fillRect(KDRect(k_batteryWidth-2*k_elementWidth, 0, k_elementWidth, k_batteryHeight), Palette::Battery);
+ ctx->fillRect(KDRect(k_batteryWidth-2*k_elementWidth, 1, k_elementWidth, k_batteryHeight-2), Palette::Battery);
ctx->fillRect(KDRect(k_batteryWidth-k_elementWidth, (k_batteryHeight-k_capHeight)/2, k_elementWidth, k_capHeight), Palette::Battery);
}
diff --git a/apps/battery_view.h b/apps/battery_view.h
index 5c1d373aa74..7d91fa929b4 100644
--- a/apps/battery_view.h
+++ b/apps/battery_view.h
@@ -20,10 +20,10 @@ class BatteryView : public TransparentView {
constexpr static int k_tickHeight = 6;
constexpr static int k_tickWidth = 8;
private:
- constexpr static KDCoordinate k_batteryHeight = 8;
- constexpr static KDCoordinate k_batteryWidth = 15;
+ constexpr static KDCoordinate k_batteryHeight = 9;
+ constexpr static KDCoordinate k_batteryWidth = 16;
constexpr static KDCoordinate k_elementWidth = 1;
- constexpr static KDCoordinate k_capHeight = 4;
+ constexpr static KDCoordinate k_capHeight = 3;
constexpr static KDCoordinate k_separatorThickness = Metric::CellSeparatorThickness;
Ion::Battery::Charge m_chargeState;
bool m_isCharging;
diff --git a/apps/calculation/Makefile b/apps/calculation/Makefile
index 43f8f92c3fd..a75d97dd85e 100644
--- a/apps/calculation/Makefile
+++ b/apps/calculation/Makefile
@@ -19,6 +19,7 @@ app_calculation_src = $(addprefix apps/calculation/,\
additional_outputs/list_controller.cpp \
additional_outputs/matrix_list_controller.cpp \
additional_outputs/rational_list_controller.cpp \
+ additional_outputs/second_degree_list_controller.cpp \
additional_outputs/trigonometry_graph_cell.cpp \
additional_outputs/trigonometry_list_controller.cpp \
additional_outputs/trigonometry_model.cpp \
diff --git a/apps/calculation/additional_outputs/second_degree_list_controller.cpp b/apps/calculation/additional_outputs/second_degree_list_controller.cpp
new file mode 100644
index 00000000000..afd9f1efa9d
--- /dev/null
+++ b/apps/calculation/additional_outputs/second_degree_list_controller.cpp
@@ -0,0 +1,320 @@
+#include "../app.h"
+#include
+#include "../../shared/poincare_helpers.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "second_degree_list_controller.h"
+
+using namespace Poincare;
+using namespace Shared;
+
+namespace Calculation {
+
+void SecondDegreeListController::setExpression(Poincare::Expression e) {
+ ExpressionsListController::setExpression(e);
+ assert(!m_expression.isUninitialized());
+
+ Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients];
+
+ Context * context = App::app()->localContext();
+ Preferences * preferences = Preferences::sharedPreferences();
+ Poincare::ExpressionNode::ReductionContext reductionContext = Poincare::ExpressionNode::ReductionContext(context,
+ preferences->complexFormat(), preferences->angleUnit(),
+ GlobalPreferences::sharedGlobalPreferences()->unitFormat(),
+ ExpressionNode::ReductionTarget::SystemForApproximation,
+ ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition,
+ Poincare::ExpressionNode::UnitConversion::Default);
+
+ PoincareHelpers::Reduce(&m_expression, context, ExpressionNode::ReductionTarget::SystemForAnalysis);
+
+ int degree = m_expression.getPolynomialReducedCoefficients(
+ "x",
+ polynomialCoefficients,
+ context,
+ Expression::UpdatedComplexFormatWithExpressionInput(preferences->complexFormat(), m_expression, context),
+ preferences->angleUnit(),
+ GlobalPreferences::sharedGlobalPreferences()->unitFormat(),
+ ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
+
+ assert(degree == 2);
+
+ Expression a = polynomialCoefficients[2];
+ Expression b = polynomialCoefficients[1];
+ Expression c = polynomialCoefficients[0];
+
+ Expression delta = Subtraction::Builder(Power::Builder(b.clone(), Rational::Builder(2)), Multiplication::Builder(Rational::Builder(4), a.clone(), c.clone()));
+ PoincareHelpers::Simplify(&delta, context, ExpressionNode::ReductionTarget::SystemForApproximation);
+
+ // Alpha is -b/2a, but because after we use -α, we immediately store -α=-(-b/2a)=b/2a.
+ Expression minusAlpha = Division::Builder(b.clone(), Multiplication::Builder(Rational::Builder(2), a.clone()));
+ PoincareHelpers::Reduce(&minusAlpha, context, ExpressionNode::ReductionTarget::SystemForApproximation);
+
+ // Same thing for β
+ Expression minusBeta = Division::Builder(delta.clone(), Multiplication::Builder(Rational::Builder(4), a.clone()));
+ PoincareHelpers::Reduce(&minusBeta, context, ExpressionNode::ReductionTarget::SystemForApproximation);
+
+ enum MultiplicationTypeForA {
+ Nothing,
+ Minus,
+ Parenthesis,
+ Normal
+ };
+
+ MultiplicationTypeForA multiplicationTypeForA;
+
+ if (a.type() == ExpressionNode::Type::Rational && static_cast(a).isOne()) {
+ multiplicationTypeForA = MultiplicationTypeForA::Nothing;
+ } else if(a.type() == ExpressionNode::Type::Rational && static_cast(a).isMinusOne()){
+ multiplicationTypeForA = MultiplicationTypeForA::Minus;
+ } else if (a.type() == ExpressionNode::Type::Addition) {
+ multiplicationTypeForA = MultiplicationTypeForA::Parenthesis;
+ } else {
+ multiplicationTypeForA = MultiplicationTypeForA::Normal;
+ }
+
+ PoincareHelpers::Simplify(&a, context, ExpressionNode::ReductionTarget::User);
+
+ /*
+ * Because when can't apply reduce or simplify to keep the
+ * canonized form we must beautify the expression manually
+ */
+
+ Expression xMinusAlphaPowerTwo;
+ Expression alpha = getOppositeIfExists(minusAlpha, &reductionContext);
+
+ if (alpha.isUninitialized()) {
+ PoincareHelpers::Simplify(&minusAlpha, context, ExpressionNode::ReductionTarget::User);
+ xMinusAlphaPowerTwo = Power::Builder(Parenthesis::Builder(Addition::Builder(Symbol::Builder("x", strlen("x")), minusAlpha)), Rational::Builder(2));
+ } else {
+ PoincareHelpers::Simplify(&alpha, context, ExpressionNode::ReductionTarget::User);
+ xMinusAlphaPowerTwo = Power::Builder(Parenthesis::Builder(Subtraction::Builder(Symbol::Builder("x", strlen("x")), alpha)), Rational::Builder(2));
+ }
+
+ Expression xMinusAlphaPowerTwoWithFactor;
+
+ switch (multiplicationTypeForA)
+ {
+ case MultiplicationTypeForA::Nothing:
+ xMinusAlphaPowerTwoWithFactor = xMinusAlphaPowerTwo;
+ break;
+ case MultiplicationTypeForA::Minus:
+ xMinusAlphaPowerTwoWithFactor = Opposite::Builder(xMinusAlphaPowerTwo);
+ break;
+ case MultiplicationTypeForA::Parenthesis:
+ xMinusAlphaPowerTwoWithFactor = Multiplication::Builder(Parenthesis::Builder(a.clone()), xMinusAlphaPowerTwo);
+ break;
+ case MultiplicationTypeForA::Normal:
+ xMinusAlphaPowerTwoWithFactor = Multiplication::Builder(a.clone(), xMinusAlphaPowerTwo);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ Expression canonized;
+ PoincareHelpers::Simplify(&minusBeta, context, ExpressionNode::ReductionTarget::User);
+ Expression beta = getOppositeIfExists(minusBeta, &reductionContext);
+ if (beta.isUninitialized()) {
+ if (minusBeta.type() == ExpressionNode::Type::Addition || minusBeta.type() == ExpressionNode::Type::Subtraction) {
+ canonized = Subtraction::Builder(xMinusAlphaPowerTwoWithFactor, Parenthesis::Builder(minusBeta));
+ } else {
+ canonized = Subtraction::Builder(xMinusAlphaPowerTwoWithFactor, minusBeta);
+ }
+ } else {
+ PoincareHelpers::Simplify(&beta, context, ExpressionNode::ReductionTarget::User);
+ canonized = Addition::Builder(xMinusAlphaPowerTwoWithFactor, beta);
+ }
+
+ Expression x0;
+ Expression x1;
+
+ if (delta.nullStatus(context) == ExpressionNode::NullStatus::Null) {
+ // x0 = x1 = -b/(2a)
+ x0 = Division::Builder(Opposite::Builder(b.clone()), Multiplication::Builder(Rational::Builder(2), a.clone()));
+ m_numberOfSolutions = 1;
+ PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::SystemForApproximation);
+ } else {
+ // x0 = (-b-sqrt(delta))/(2a)
+ x0 = Division::Builder(Subtraction::Builder(Opposite::Builder(b.clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), a.clone()));
+ // x1 = (-b+sqrt(delta))/(2a)
+ x1 = Division::Builder(Addition::Builder(Opposite::Builder(b.clone()), SquareRoot::Builder(delta.clone())), Multiplication::Builder(Rational::Builder(2), a.clone()));
+ m_numberOfSolutions = 2;
+ PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::SystemForApproximation);
+ PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::SystemForApproximation);
+ if (x0.type() == ExpressionNode::Type::Unreal) {
+ assert(x1.type() == ExpressionNode::Type::Unreal);
+ m_numberOfSolutions = 0;
+ }
+ }
+
+ Expression factorized;
+
+ if (m_numberOfSolutions == 2) {
+ Expression firstFactor;
+ Expression secondFactor;
+
+ Expression x0Opposite = getOppositeIfExists(x0, &reductionContext);
+ if (x0Opposite.isUninitialized()) {
+ PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
+ if (x0.type() == ExpressionNode::Type::Addition || x0.type() == ExpressionNode::Type::Subtraction) {
+ firstFactor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), Parenthesis::Builder(x0.clone()));
+ } else {
+ firstFactor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0.clone());
+ }
+ } else {
+ if (x0Opposite.type() == ExpressionNode::Type::Addition || x0Opposite.type() == ExpressionNode::Type::Subtraction) {
+ x0Opposite = Parenthesis::Builder(x0Opposite.clone());
+ }
+ firstFactor = Addition::Builder(Symbol::Builder("x", strlen("x")), x0Opposite.clone());
+ }
+
+ Expression x1Opposite = getOppositeIfExists(x1, &reductionContext);
+ if (x1Opposite.isUninitialized()) {
+ PoincareHelpers::Simplify(&x1, context, ExpressionNode::ReductionTarget::User);
+ if (x1.type() == ExpressionNode::Type::Addition || x1.type() == ExpressionNode::Type::Subtraction) {
+ secondFactor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), Parenthesis::Builder(x1.clone()));
+ } else {
+ secondFactor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x1.clone());
+ }
+ } else {
+ PoincareHelpers::Simplify(&x1Opposite, context, ExpressionNode::ReductionTarget::User);
+ if (x1Opposite.type() == ExpressionNode::Type::Addition || x1Opposite.type() == ExpressionNode::Type::Subtraction) {
+ x1Opposite = Parenthesis::Builder(x1Opposite.clone());
+ }
+ secondFactor = Addition::Builder(Symbol::Builder("x", strlen("x")), x1Opposite.clone());
+ }
+
+ Expression solutionProduct = Multiplication::Builder(Parenthesis::Builder(firstFactor), Parenthesis::Builder(secondFactor));
+ switch (multiplicationTypeForA)
+ {
+ case MultiplicationTypeForA::Nothing:
+ factorized = solutionProduct;
+ break;
+ case MultiplicationTypeForA::Minus:
+ factorized = Opposite::Builder(solutionProduct);
+ break;
+ case MultiplicationTypeForA::Parenthesis:
+ factorized = Multiplication::Builder(Parenthesis::Builder(a.clone()), solutionProduct);
+ break;
+ case MultiplicationTypeForA::Normal:
+ factorized = Multiplication::Builder(a.clone(), solutionProduct);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ } else if (m_numberOfSolutions == 1) {
+ Expression x0Opposite = getOppositeIfExists(x0, &reductionContext);
+ Expression factor;
+
+ if (x0Opposite.isUninitialized()) {
+ PoincareHelpers::Simplify(&x0, context, ExpressionNode::ReductionTarget::User);
+ if (x0.type() == ExpressionNode::Type::Addition || x0.type() == ExpressionNode::Type::Subtraction) {
+ factor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), Parenthesis::Builder(x0.clone()));
+ } else {
+ factor = Subtraction::Builder(Symbol::Builder("x", strlen("x")), x0.clone());
+ }
+ } else {
+ PoincareHelpers::Simplify(&x0Opposite, context, ExpressionNode::ReductionTarget::User);
+ factor = Addition::Builder(Symbol::Builder("x", strlen("x")), x0Opposite.clone());
+ }
+
+ Expression solutionProduct = Power::Builder(Parenthesis::Builder(factor), Rational::Builder(2));
+ switch (multiplicationTypeForA)
+ {
+ case MultiplicationTypeForA::Nothing:
+ factorized = solutionProduct;
+ break;
+ case MultiplicationTypeForA::Minus:
+ factorized = Opposite::Builder(solutionProduct);
+ break;
+ case MultiplicationTypeForA::Parenthesis:
+ factorized = Multiplication::Builder(Parenthesis::Builder(a.clone()), solutionProduct);
+ break;
+ case MultiplicationTypeForA::Normal:
+ factorized = Multiplication::Builder(a.clone(), solutionProduct);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+
+ PoincareHelpers::Simplify(&delta, context, ExpressionNode::ReductionTarget::User);
+
+ m_layouts[0] = PoincareHelpers::CreateLayout(canonized);
+ if (m_numberOfSolutions > 0) {
+ m_layouts[1] = PoincareHelpers::CreateLayout(factorized);
+ m_layouts[2] = PoincareHelpers::CreateLayout(delta);
+ m_layouts[3] = PoincareHelpers::CreateLayout(x0);
+ if (m_numberOfSolutions > 1) {
+ m_layouts[4] = PoincareHelpers::CreateLayout(x1);
+ }
+ } else {
+ m_layouts[1] = PoincareHelpers::CreateLayout(delta);
+ }
+}
+
+Expression SecondDegreeListController::getOppositeIfExists(Expression e, Poincare::ExpressionNode::ReductionContext * reductionContext) {
+ if (e.isNumber() && e.sign(reductionContext->context()) == ExpressionNode::Sign::Negative) {
+ Number n = static_cast(e);
+ return std::move(n.setSign(ExpressionNode::Sign::Positive));
+ } else if(e.type() == ExpressionNode::Type::Opposite) {
+ return std::move(e.childAtIndex(0).clone());
+ } else if (e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() > 0 && e.childAtIndex(0).isNumber() && e.childAtIndex(0).sign(reductionContext->context()) == ExpressionNode::Sign::Negative) {
+ Multiplication m = static_cast(e);
+ if (m.childAtIndex(0).type() == ExpressionNode::Type::Rational && static_cast(e).isMinusOne()) {
+ // The negative numeral factor is -1, we just remove it
+ m.removeChildAtIndexInPlace(0);
+ } else {
+ Expression firstChild = m.childAtIndex(0);
+ Number n = static_cast(firstChild);
+ m.childAtIndex(0).setChildrenInPlace(n.setSign(ExpressionNode::Sign::Positive));
+ }
+ PoincareHelpers::Simplify(&m, reductionContext->context(), ExpressionNode::ReductionTarget::User);
+ return std::move(m);
+ }
+ return Expression();
+}
+
+I18n::Message SecondDegreeListController::messageAtIndex(int index) {
+ if (m_numberOfSolutions > 0) {
+ if (index == 0) {
+ return I18n::Message::CanonicalForm;
+ }
+ if (index == 1) {
+ return I18n::Message::FactorizedForm;
+ }
+ if (index == 2) {
+ return I18n::Message::Discriminant;
+ }
+ if (index == 3) {
+ if (m_numberOfSolutions == 1) {
+ return I18n::Message::OnlyRoot;
+ } else {
+ return I18n::Message::FirstRoot;
+ }
+ }
+ return I18n::Message::SecondRoot;
+ } else {
+ switch (index) {
+ case 0:
+ return I18n::Message::CanonicalForm;
+ default:
+ return I18n::Message::Discriminant;
+ }
+ }
+}
+
+}
diff --git a/apps/calculation/additional_outputs/second_degree_list_controller.h b/apps/calculation/additional_outputs/second_degree_list_controller.h
new file mode 100644
index 00000000000..89812b71043
--- /dev/null
+++ b/apps/calculation/additional_outputs/second_degree_list_controller.h
@@ -0,0 +1,26 @@
+#ifndef CALCULATION_ADDITIONAL_OUTPUTS_SECOND_DEGREE_CONTROLLER_H
+#define CALCULATION_ADDITIONAL_OUTPUTS_SECOND_DEGREE_CONTROLLER_H
+
+#include "expressions_list_controller.h"
+
+namespace Calculation {
+
+class SecondDegreeListController : public ExpressionsListController {
+public:
+ SecondDegreeListController(EditExpressionController * editExpressionController) :
+ ExpressionsListController(editExpressionController),
+ m_numberOfSolutions(0) {}
+
+ void setExpression(Poincare::Expression e) override;
+
+private:
+ Poincare::Expression getOppositeIfExists(Poincare::Expression e, Poincare::ExpressionNode::ReductionContext * reductionContext);
+ I18n::Message messageAtIndex(int index) override;
+ int m_numberOfSolutions;
+};
+
+}
+
+#endif
+
+
diff --git a/apps/calculation/additional_outputs/trigonometry_list_controller.cpp b/apps/calculation/additional_outputs/trigonometry_list_controller.cpp
index b8bdcb0764e..354cbc7391f 100644
--- a/apps/calculation/additional_outputs/trigonometry_list_controller.cpp
+++ b/apps/calculation/additional_outputs/trigonometry_list_controller.cpp
@@ -1,16 +1,63 @@
#include "trigonometry_list_controller.h"
#include "../app.h"
+#include
+#include "../../shared/poincare_helpers.h"
using namespace Poincare;
namespace Calculation {
-void TrigonometryListController::setExpression(Poincare::Expression e) {
+static constexpr int s_fullCircle[] = {
+ 360,
+ 2,
+ 400
+};
+
+Poincare::Constant toConstant(Expression e) {
+ return static_cast(e);
+}
+
+void TrigonometryListController::setExpression(Expression e) {
assert(e.type() == ExpressionNode::Type::Cosine || e.type() == ExpressionNode::Type::Sine);
- IllustratedListController::setExpression(e.childAtIndex(0));
- // Fill calculation store
Poincare::Context * context = App::app()->localContext();
+ Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences();
+ Preferences::AngleUnit angleUnit = preferences->angleUnit();
+
+ Expression angleExpression = e.childAtIndex(0);
+
+ Shared::PoincareHelpers::Reduce(&angleExpression, context, Poincare::ExpressionNode::ReductionTarget::SystemForAnalysis);
+
+ if ((angleUnit == Preferences::AngleUnit::Radian
+ && angleExpression.type() == ExpressionNode::Type::Multiplication
+ && angleExpression.numberOfChildren() == 2
+ && angleExpression.childAtIndex(1).type() == ExpressionNode::Type::Constant
+ && toConstant(angleExpression.childAtIndex(1)).isPi()
+ && angleExpression.childAtIndex(0).type() == ExpressionNode::Type::Rational)
+ || ((angleUnit == Preferences::AngleUnit::Degree || angleUnit == Preferences::AngleUnit::Gradian)
+ && angleExpression.type() == ExpressionNode::Type::Rational)) {
+
+ Expression extracted = angleUnit == Preferences::AngleUnit::Radian ? angleExpression.childAtIndex(0) : angleExpression;
+ Rational r = static_cast(extracted);
+
+ Integer denominator = Integer::Multiplication(r.integerDenominator(), Integer(s_fullCircle[(int) angleUnit]));
+ IntegerDivision division = Integer::Division(r.signedIntegerNumerator(), denominator);
+
+ Integer remainder = division.remainder;
+
+ Expression newAngle;
+ Integer rDenominator = r.integerDenominator();
+ Rational newCoefficient = Rational::Builder(remainder, rDenominator);
+ if (angleUnit == Preferences::AngleUnit::Radian) {
+ angleExpression = Multiplication::Builder(newCoefficient, angleExpression.childAtIndex(1));
+ } else {
+ angleExpression = newCoefficient;
+ }
+ }
+
+ IllustratedListController::setExpression(angleExpression);
+
+ // Fill calculation store
m_calculationStore.push("sin(θ)", context, CalculationHeight);
m_calculationStore.push("cos(θ)", context, CalculationHeight);
m_calculationStore.push("θ", context, CalculationHeight);
diff --git a/apps/calculation/additional_outputs/unit_list_controller.cpp b/apps/calculation/additional_outputs/unit_list_controller.cpp
index 869826d5e4f..37fdcf7763e 100644
--- a/apps/calculation/additional_outputs/unit_list_controller.cpp
+++ b/apps/calculation/additional_outputs/unit_list_controller.cpp
@@ -12,6 +12,26 @@ using namespace Shared;
namespace Calculation {
+
+UnitListController::UnitListController(EditExpressionController * editExpressionController) :
+ ExpressionsListController(editExpressionController),
+ m_dimensionMessage(I18n::Message::Default)
+{
+ m_dimensionCell.setMessageFont(KDFont::LargeFont);
+}
+
+bool UnitListController::handleEvent(Ion::Events::Event event) {
+ if (selectedRow() == 0 && (event == Ion::Events::OK || event == Ion::Events::EXE)) {
+ return true;
+ }
+
+ // HACK: Change the selected row (prevent some bugs when OK is pressed)
+ selectRow(selectedRow() - 1);
+ bool value = ListController::handleEvent(event);
+ selectRow(selectedRow() + 1);
+ return value;
+}
+
void UnitListController::setExpression(Poincare::Expression e) {
ExpressionsListController::setExpression(e);
assert(!m_expression.isUninitialized());
@@ -22,6 +42,7 @@ void UnitListController::setExpression(Poincare::Expression e) {
for (size_t i = 0; i < k_maxNumberOfRows; i++) {
expressions[i] = Expression();
}
+ m_dimensionMessage = I18n::Message::Default;
/* 1. First rows: miscellaneous classic units for some dimensions, in both
* metric and imperial units. */
@@ -37,7 +58,7 @@ void UnitListController::setExpression(Poincare::Expression e) {
GlobalPreferences::sharedGlobalPreferences()->unitFormat(),
ExpressionNode::ReductionTarget::User,
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined);
- int numberOfExpressions = Unit::SetAdditionalExpressions(units, value, expressions, k_maxNumberOfRows, reductionContext);
+ int numberOfExpressions = Unit::SetAdditionalExpressionsAndMessage(units, value, expressions, k_maxNumberOfRows, reductionContext, &m_dimensionMessage);
// 2. SI units only
assert(numberOfExpressions < k_maxNumberOfRows - 1);
@@ -89,6 +110,44 @@ void UnitListController::setExpression(Poincare::Expression e) {
}
}
+int UnitListController::numberOfRows() const {
+ int messageRow = m_dimensionMessage != I18n::Message::Default ? 1 : 0;
+ return ExpressionsListController::numberOfRows() + messageRow;
+}
+
+void UnitListController::willDisplayCellForIndex(HighlightCell * cell, int index) {
+ if (index == 0) {
+ MessageTableCell<> * messageTableCell = (MessageTableCell<> *)cell;
+ messageTableCell->setMessage(m_dimensionMessage);
+ } else {
+ ExpressionsListController::willDisplayCellForIndex(cell, index - 1);
+ }
+}
+
+KDCoordinate UnitListController::rowHeight(int index) {
+ if (index == 0) {
+ return 35;
+ } else {
+ return ExpressionsListController::rowHeight(index - 1);
+ }
+}
+
+HighlightCell * UnitListController::reusableCell(int index, int type) {
+ if (type == 0) {
+ return ExpressionsListController::reusableCell(index, type);
+ } else {
+ return &m_dimensionCell;
+ }
+}
+
+int UnitListController::typeAtLocation(int i, int j) {
+ if (j == 0) {
+ return 1;
+ } else {
+ return ExpressionsListController::typeAtLocation(i, j - 1);
+ }
+}
+
I18n::Message UnitListController::messageAtIndex(int index) {
return (I18n::Message)0;
}
diff --git a/apps/calculation/additional_outputs/unit_list_controller.h b/apps/calculation/additional_outputs/unit_list_controller.h
index 58f6d1e0d90..fb351ec320c 100644
--- a/apps/calculation/additional_outputs/unit_list_controller.h
+++ b/apps/calculation/additional_outputs/unit_list_controller.h
@@ -7,13 +7,23 @@ namespace Calculation {
class UnitListController : public ExpressionsListController {
public:
- UnitListController(EditExpressionController * editExpressionController) :
- ExpressionsListController(editExpressionController) {}
+ UnitListController(EditExpressionController * editExpressionController);
+
+ /* Responder */
+ bool handleEvent(Ion::Events::Event event) override;
void setExpression(Poincare::Expression e) override;
+ int reusableCellCount(int type) override { return type == 0 ? ExpressionsListController::reusableCellCount(type) : 1; }
+ HighlightCell * reusableCell(int index, int type) override;
+ KDCoordinate rowHeight(int j) override;
+ int typeAtLocation(int i, int j) override;
+ void willDisplayCellForIndex(HighlightCell * cell, int index) override;
+ int numberOfRows() const override;
private:
I18n::Message messageAtIndex(int index) override;
+ I18n::Message m_dimensionMessage;
+ MessageTableCell<> m_dimensionCell;
};
}
diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp
index 2c5c97d3c87..ad344c31687 100644
--- a/apps/calculation/app.cpp
+++ b/apps/calculation/app.cpp
@@ -72,7 +72,7 @@ bool App::isAcceptableExpression(const Poincare::Expression expression) {
return false;
}
}
- return !(expression.isUninitialized() || expression.type() == ExpressionNode::Type::Equal);
+ return !expression.isUninitialized();
}
void App::didBecomeActive(Window * window) {
diff --git a/apps/calculation/base.de.i18n b/apps/calculation/base.de.i18n
index 406f27e8499..419d3b96574 100644
--- a/apps/calculation/base.de.i18n
+++ b/apps/calculation/base.de.i18n
@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinante"
AdditionalInverse = "Inverse"
AdditionalRowEchelonForm = "Stufenform"
AdditionalReducedRowEchelonForm = "Reduzierte Stufenform"
-AdditionalTrace = "Spur"
\ No newline at end of file
+AdditionalTrace = "Spur"
+CanonicalForm = "Kanonische Form"
+FactorizedForm = "Factorisierte Form"
+Discriminant = "Diskriminante"
+OnlyRoot = "Wurzel"
+FirstRoot = "Erste Wurzel"
+SecondRoot = "Zweite Wurzel"
diff --git a/apps/calculation/base.en.i18n b/apps/calculation/base.en.i18n
index 967c0905063..23df23e3a55 100644
--- a/apps/calculation/base.en.i18n
+++ b/apps/calculation/base.en.i18n
@@ -12,3 +12,9 @@ AdditionalInverse = "Inverse"
AdditionalRowEchelonForm = "Row echelon form"
AdditionalReducedRowEchelonForm = "Reduced row echelon form"
AdditionalTrace = "Trace"
+CanonicalForm = "Canonical form"
+FactorizedForm = "Factorized form"
+Discriminant = "Discriminant"
+OnlyRoot = "Root"
+FirstRoot = "First root"
+SecondRoot = "Second root"
diff --git a/apps/calculation/base.es.i18n b/apps/calculation/base.es.i18n
index 057481a0dbd..1df949c380c 100644
--- a/apps/calculation/base.es.i18n
+++ b/apps/calculation/base.es.i18n
@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinante"
AdditionalInverse = "Inversa"
AdditionalRowEchelonForm = "Matriz escalonada"
AdditionalReducedRowEchelonForm = "Matriz escalonada reducida"
-AdditionalTrace = "Traza"
\ No newline at end of file
+AdditionalTrace = "Traza"
+CanonicalForm = "Forma canónica"
+FactorizedForm = "Forma factorizada"
+Discriminant = "Discriminante"
+OnlyRoot = "Raíz"
+FirstRoot = "Primera raíz"
+SecondRoot = "Segunda raíz"
diff --git a/apps/calculation/base.fr.i18n b/apps/calculation/base.fr.i18n
index 0e155e29474..2b9e7bdac8b 100644
--- a/apps/calculation/base.fr.i18n
+++ b/apps/calculation/base.fr.i18n
@@ -11,4 +11,10 @@ AdditionalDeterminant = "Déterminant"
AdditionalInverse = "Inverse"
AdditionalRowEchelonForm = "Forme échelonnée"
AdditionalReducedRowEchelonForm = "Forme échelonnée réduite"
-AdditionalTrace = "Trace"
\ No newline at end of file
+AdditionalTrace = "Trace"
+CanonicalForm = "Forme canonique"
+FactorizedForm = "Forme factorisée"
+Discriminant = "Discriminant"
+OnlyRoot = "Racine"
+FirstRoot = "Première racine"
+SecondRoot = "Seconde racine"
diff --git a/apps/calculation/base.hu.i18n b/apps/calculation/base.hu.i18n
index 39397adee2f..4c6cfc4a020 100644
--- a/apps/calculation/base.hu.i18n
+++ b/apps/calculation/base.hu.i18n
@@ -1,14 +1,20 @@
-CalculApp = "Számolás"
-CalculAppCapital = "SZÁMOLÁS"
-AdditionalResults = "További eredmények"
-DecimalBase = "Decimális"
-HexadecimalBase = "Hexadecimális"
-BinaryBase = "Bináris"
-PrimeFactors = "Alapvetö tényezök"
-MixedFraction = "Vegyes frakció"
-EuclideanDivision = "Euklideszi osztás"
-AdditionalDeterminant = "Meghatározó"
-AdditionalInverse = "inverz"
-AdditionalRowEchelonForm = "Sor echelon forma"
-AdditionalReducedRowEchelonForm = "Csökkentett sorú Echelon forma"
-AdditionalTrace = "Nyomkövetés"
+CalculApp = "Számolás"
+CalculAppCapital = "SZÁMOLÁS"
+AdditionalResults = "További eredmények"
+DecimalBase = "Decimális"
+HexadecimalBase = "Hexadecimális"
+BinaryBase = "Bináris"
+PrimeFactors = "Alapvetö tényezök"
+MixedFraction = "Vegyes frakció"
+EuclideanDivision = "Euklideszi osztás"
+AdditionalDeterminant = "Meghatározó"
+AdditionalInverse = "inverz"
+AdditionalRowEchelonForm = "Sor echelon forma"
+AdditionalReducedRowEchelonForm = "Csökkentett sorú Echelon forma"
+AdditionalTrace = "Nyomkövetés"
+CanonicalForm = "Kanonikus forma"
+FactorizedForm = "Factorizált forma"
+Discriminant = "Discriminant"
+OnlyRoot = "Gyökér"
+FirstRoot = "Első gyökér"
+SecondRoot = "Második gyökér"
diff --git a/apps/calculation/base.it.i18n b/apps/calculation/base.it.i18n
index ca41028937e..62620d05c9c 100644
--- a/apps/calculation/base.it.i18n
+++ b/apps/calculation/base.it.i18n
@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinante"
AdditionalInverse = "Inversa"
AdditionalRowEchelonForm = "Matrice a scalini"
AdditionalReducedRowEchelonForm = "Matrice ridotta a scalini"
-AdditionalTrace = "Traccia"
\ No newline at end of file
+AdditionalTrace = "Traccia"
+CanonicalForm = "Forma canonica"
+FactorizedForm = "Forma fattorizzata"
+Discriminant = "Discriminante"
+OnlyRoot = "Radice"
+FirstRoot = "Prima radice"
+SecondRoot = "Seconda radice"
diff --git a/apps/calculation/base.nl.i18n b/apps/calculation/base.nl.i18n
index 51e412cb40c..1b286d49b9b 100644
--- a/apps/calculation/base.nl.i18n
+++ b/apps/calculation/base.nl.i18n
@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinant"
AdditionalInverse = "Inverse"
AdditionalRowEchelonForm = "Echelonvorm"
AdditionalReducedRowEchelonForm = "Gereduceerde echelonvorm"
-AdditionalTrace = "Spoor"
\ No newline at end of file
+AdditionalTrace = "Spoor"
+CanonicalForm = "Canonische vorm"
+FactorizedForm = "Factorized vorm"
+Discriminant = "Discriminant"
+OnlyRoot = "Wortel"
+FirstRoot = "Eerste wortel"
+SecondRoot = "Tweede wortel"
diff --git a/apps/calculation/base.pt.i18n b/apps/calculation/base.pt.i18n
index 941363a04b7..15abb51a7e1 100644
--- a/apps/calculation/base.pt.i18n
+++ b/apps/calculation/base.pt.i18n
@@ -11,4 +11,10 @@ AdditionalDeterminant = "Determinante"
AdditionalInverse = "Matriz inversa"
AdditionalRowEchelonForm = "Matriz escalonada"
AdditionalReducedRowEchelonForm = "Matriz escalonada reduzida"
-AdditionalTrace = "Traço"
\ No newline at end of file
+AdditionalTrace = "Traço"
+CanonicalForm = "Forma canónica"
+FactorizedForm = "Factorized form"
+Discriminant = "Discriminante"
+OnlyRoot = "Raiz"
+FirstRoot = "Primeira raiz"
+SecondRoot = "Segunda raiz"
diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp
index c293cbbe841..b67efc2b89b 100644
--- a/apps/calculation/calculation.cpp
+++ b/apps/calculation/calculation.cpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -256,8 +257,9 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
if (o.hasUnit()) {
Expression unit;
PoincareHelpers::ReduceAndRemoveUnit(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User, &unit, ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None);
- double value = PoincareHelpers::ApproximateToScalar(o, App::app()->localContext());
- return (Unit::ShouldDisplayAdditionalOutputs(value, unit, GlobalPreferences::sharedGlobalPreferences()->unitFormat())) ? AdditionalInformationType::Unit : AdditionalInformationType::None;
+ UnitNode::Vector vector = UnitNode::Vector::FromBaseUnits(unit);
+ const Unit::Representative * representative = Unit::Representative::RepresentativeForDimension(vector);
+ return representative != nullptr ? AdditionalInformationType::Unit : AdditionalInformationType::None;
}
if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) {
return AdditionalInformationType::Integer;
@@ -272,6 +274,9 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
if (o.type() == ExpressionNode::Type::Matrix) {
return AdditionalInformationType::Matrix;
}
+ if (o.polynomialDegree(context, "x") == 2) {
+ return AdditionalInformationType::SecondDegree;
+ }
return AdditionalInformationType::None;
}
diff --git a/apps/calculation/calculation.h b/apps/calculation/calculation.h
index be7f87c9bcc..4c026cbc42b 100644
--- a/apps/calculation/calculation.h
+++ b/apps/calculation/calculation.h
@@ -39,6 +39,7 @@ friend CalculationStore;
None = 0,
Integer,
Rational,
+ SecondDegree,
Trigonometry,
Unit,
Matrix,
diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp
index e0dcc12f161..eee89ac89ed 100644
--- a/apps/calculation/calculation_store.cpp
+++ b/apps/calculation/calculation_store.cpp
@@ -7,6 +7,39 @@
#include "../exam_mode_configuration.h"
#include
+#if defined _FXCG || defined NSPIRE_NEWLIB
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static KDCoordinate dummyHeight(::Calculation::Calculation * c, bool expanded) {
+ bool b;
+ Poincare::Layout l = c->createExactOutputLayout(&b);
+ if (!b) {
+ l=c->createInputLayout();
+ }
+ KDSize s = l.layoutSize();
+ const int bordersize = 10;
+ int h = s.height() + bordersize;
+ const int maxheight = 64;
+ if (h > maxheight) {
+ return maxheight;
+ }
+ return h;
+}
+
+extern void * last_calculation_history;
+void * last_calculation_history = 0;
+const char * retrieve_calc_history();
+
+#endif
+
using namespace Poincare;
using namespace Shared;
@@ -16,16 +49,55 @@ CalculationStore::CalculationStore(char * buffer, int size) :
m_buffer(buffer),
m_bufferSize(size),
m_calculationAreaEnd(m_buffer),
- m_numberOfCalculations(0)
+ m_numberOfCalculations(0),
+ m_trashIndex(-1)
{
assert(m_buffer != nullptr);
assert(m_bufferSize > 0);
+#if defined _FXCG || defined NSPIRE_NEWLIB
+ if (last_calculation_history == 0){
+ // Restore from scriptstore
+ const char * buf=retrieve_calc_history();
+ if (buf) {
+ Shared::GlobalContext globalContext;
+ char * ptr=(char *)buf;
+ for (;*ptr;) {
+ for (;*ptr;++ptr) {
+ if (*ptr=='\n') {
+ break;
+ }
+ }
+ char c = *ptr;
+ *ptr=0;
+ if (ptr > buf) {
+ push(buf,&globalContext, dummyHeight);
+ }
+ *ptr = c;
+ ++ptr;
+ buf = ptr;
+ }
+ }
+ last_calculation_history = (void *) this;
+ }
+#endif
}
-// Returns an expiring pointer to the calculation of index i
+// Returns an expiring pointer to the calculation of index i, and ignore the trash
ExpiringPointer CalculationStore::calculationAtIndex(int i) {
+#if defined _FXCG || defined NSPIRE_NEWLIB
+ last_calculation_history = (void *) this;
+#endif
+ if (m_trashIndex == -1 || i < m_trashIndex) {
+ return realCalculationAtIndex(i);
+ } else {
+ return realCalculationAtIndex(i + 1);
+ }
+}
+
+// Returns an expiring pointer to the real calculation of index i
+ExpiringPointer CalculationStore::realCalculationAtIndex(int i) {
assert(i >= 0 && i < m_numberOfCalculations);
- // m_buffer is the adress of the oldest calculation in calculation store
+ // m_buffer is the address of the oldest calculation in calculation store
Calculation * c = (Calculation *) m_buffer;
if (i != m_numberOfCalculations-1) {
// The calculation we want is not the oldest one so we get its pointer
@@ -36,12 +108,13 @@ ExpiringPointer CalculationStore::calculationAtIndex(int i) {
// Pushes an expression in the store
ExpiringPointer CalculationStore::push(const char * text, Context * context, HeightComputer heightComputer) {
+ emptyTrash();
/* Compute ans now, before the buffer is updated and before the calculation
* might be deleted */
Expression ans = ansExpression(context);
/* Prepare the buffer for the new calculation
- *The minimal size to store the new calculation is the minimal size of a calculation plus the pointer to its end */
+ * The minimal size to store the new calculation is the minimal size of a calculation plus the pointer to its end */
int minSize = Calculation::MinimalSize() + sizeof(Calculation *);
assert(m_bufferSize > minSize);
while (remainingBufferSize() < minSize) {
@@ -100,9 +173,9 @@ ExpiringPointer CalculationStore::push(const char * text, Context *
numberOfSignificantDigits = Poincare::Preferences::sharedPreferences()->numberOfSignificantDigits();
}
if (!pushSerializeExpression(outputs[i], beginingOfFreeSpace, &endOfFreeSpace, numberOfSignificantDigits)) {
- /* If the exat/approximate output does not fit in the store (event if the
+ /* If the exact/approximate output does not fit in the store (event if the
* current calculation is the only calculation), replace the output with
- * undef if it fits, else replace the whole calcualtion with undef. */
+ * undef if it fits, else replace the whole calculation with undef. */
Expression undef = Undefined::Builder();
if (!pushSerializeExpression(undef, beginingOfFreeSpace, &endOfFreeSpace)) {
return emptyStoreAndPushUndef(context, heightComputer);
@@ -132,15 +205,23 @@ ExpiringPointer CalculationStore::push(const char * text, Context *
// Delete the calculation of index i
void CalculationStore::deleteCalculationAtIndex(int i) {
+ if (m_trashIndex != -1) {
+ emptyTrash();
+ }
+ m_trashIndex = i;
+}
+
+// Delete the calculation of index i, internal algorithm
+void CalculationStore::realDeleteCalculationAtIndex(int i) {
assert(i >= 0 && i < m_numberOfCalculations);
if (i == 0) {
- ExpiringPointer lastCalculationPointer = calculationAtIndex(0);
+ ExpiringPointer lastCalculationPointer = realCalculationAtIndex(0);
m_calculationAreaEnd = (char *)(lastCalculationPointer.pointer());
m_numberOfCalculations--;
return;
}
- char * calcI = (char *)calculationAtIndex(i).pointer();
- char * nextCalc = (char *) calculationAtIndex(i-1).pointer();
+ char * calcI = (char *)realCalculationAtIndex(i).pointer();
+ char * nextCalc = (char *) realCalculationAtIndex(i-1).pointer();
assert(m_calculationAreaEnd >= nextCalc);
size_t slidingSize = m_calculationAreaEnd - nextCalc;
// Slide the i-1 most recent calculations right after the i+1'th
@@ -154,13 +235,14 @@ void CalculationStore::deleteCalculationAtIndex(int i) {
// Delete the oldest calculation in the store and returns the amount of space freed by the operation
size_t CalculationStore::deleteOldestCalculation() {
char * oldBufferEnd = (char *) m_calculationAreaEnd;
- deleteCalculationAtIndex(numberOfCalculations()-1);
+ realDeleteCalculationAtIndex(numberOfCalculations()-1);
char * newBufferEnd = (char *) m_calculationAreaEnd;
return oldBufferEnd - newBufferEnd;
}
// Delete all calculations
void CalculationStore::deleteAll() {
+ m_trashIndex = -1;
m_calculationAreaEnd = m_buffer;
m_numberOfCalculations = 0;
}
@@ -177,8 +259,8 @@ Expression CalculationStore::ansExpression(Context * context) {
* parsed), ans is replaced by the approximation output when any Store or
* Equal expression appears. */
Expression e = mostRecentCalculation->exactOutput();
- bool exactOuptutInvolvesStoreEqual = e.type() == ExpressionNode::Type::Store || e.type() == ExpressionNode::Type::Equal;
- if (mostRecentCalculation->input().recursivelyMatches(Expression::IsApproximate, context) || exactOuptutInvolvesStoreEqual) {
+ bool exactOutputInvolvesStoreEqual = e.type() == ExpressionNode::Type::Store || e.type() == ExpressionNode::Type::Equal;
+ if (mostRecentCalculation->input().recursivelyMatches(Expression::IsApproximate, context) || exactOutputInvolvesStoreEqual) {
return mostRecentCalculation->approximateOutput(context, Calculation::NumberOfSignificantDigits::Maximal);
}
return mostRecentCalculation->exactOutput();
@@ -200,6 +282,12 @@ bool CalculationStore::pushSerializeExpression(Expression e, char * location, ch
return expressionIsPushed;
}
+void CalculationStore::emptyTrash() {
+ if (m_trashIndex != -1) {
+ realDeleteCalculationAtIndex(m_trashIndex);
+ m_trashIndex = -1;
+ }
+}
Shared::ExpiringPointer CalculationStore::emptyStoreAndPushUndef(Context * context, HeightComputer heightComputer) {
@@ -213,7 +301,7 @@ Shared::ExpiringPointer CalculationStore::emptyStoreAndPushUndef(Co
void CalculationStore::recomputeMemoizedPointersAfterCalculationIndex(int index) {
assert(index < m_numberOfCalculations);
// Clear pointer and recompute new ones
- Calculation * c = calculationAtIndex(index).pointer();
+ Calculation * c = realCalculationAtIndex(index).pointer();
Calculation * nextCalc;
while (index != 0) {
nextCalc = c->next();
diff --git a/apps/calculation/calculation_store.h b/apps/calculation/calculation_store.h
index 53bc3fdf4f6..134a9fbb853 100644
--- a/apps/calculation/calculation_store.h
+++ b/apps/calculation/calculation_store.h
@@ -41,11 +41,15 @@ class CalculationStore {
void deleteCalculationAtIndex(int i);
void deleteAll();
int remainingBufferSize() const { assert(m_calculationAreaEnd >= m_buffer); return m_bufferSize - (m_calculationAreaEnd - m_buffer) - m_numberOfCalculations*sizeof(Calculation*); }
- int numberOfCalculations() const { return m_numberOfCalculations; }
+ int numberOfCalculations() const { return m_numberOfCalculations - (m_trashIndex != -1); }
Poincare::Expression ansExpression(Poincare::Context * context);
int bufferSize() { return m_bufferSize; }
+ void reinsertTrash() { m_trashIndex = -1; }
private:
+ void emptyTrash();
+ Shared::ExpiringPointer realCalculationAtIndex(int i);
+ void realDeleteCalculationAtIndex(int i);
class CalculationIterator {
public:
@@ -70,6 +74,7 @@ class CalculationStore {
int m_bufferSize;
const char * m_calculationAreaEnd;
int m_numberOfCalculations;
+ int m_trashIndex;
size_t deleteOldestCalculation();
char * addressOfPointerToCalculationOfIndex(int i) {return m_buffer + m_bufferSize - (m_numberOfCalculations - i)*sizeof(Calculation *);}
diff --git a/apps/calculation/edit_expression_controller.cpp b/apps/calculation/edit_expression_controller.cpp
index 7f747d3598f..9d999bf196e 100644
--- a/apps/calculation/edit_expression_controller.cpp
+++ b/apps/calculation/edit_expression_controller.cpp
@@ -68,6 +68,15 @@ void EditExpressionController::memoizeInput() {
*m_cacheBufferInformation = m_contentView.expressionField()->moveCursorAndDumpContent(m_cacheBuffer, k_cacheBufferSize);
}
+bool EditExpressionController::handleEvent(Ion::Events::Event event) {
+ if (event == Ion::Events::ShiftBack) {
+ m_historyController->reinsertTrash();
+ m_historyController->reload();
+ return true;
+ }
+ return false;
+}
+
void EditExpressionController::viewWillAppear() {
m_historyController->viewWillAppear();
}
diff --git a/apps/calculation/edit_expression_controller.h b/apps/calculation/edit_expression_controller.h
index 32a6ec84cb2..9e788faa361 100644
--- a/apps/calculation/edit_expression_controller.h
+++ b/apps/calculation/edit_expression_controller.h
@@ -31,6 +31,7 @@ class EditExpressionController : public ViewController, public Shared::TextField
void insertTextBody(const char * text);
void restoreInput();
void memoizeInput();
+ bool handleEvent(Ion::Events::Event event) override;
/* TextFieldDelegate */
bool textFieldDidReceiveEvent(::TextField * textField, Ion::Events::Event event) override;
diff --git a/apps/calculation/history_controller.cpp b/apps/calculation/history_controller.cpp
index 6d51e7862f9..9a868730973 100644
--- a/apps/calculation/history_controller.cpp
+++ b/apps/calculation/history_controller.cpp
@@ -16,6 +16,7 @@ HistoryController::HistoryController(EditExpressionController * editExpressionCo
m_complexController(editExpressionController),
m_integerController(editExpressionController),
m_rationalController(editExpressionController),
+ m_secondDegreeController(editExpressionController),
m_trigonometryController(editExpressionController),
m_unitController(editExpressionController),
m_matrixController(editExpressionController)
@@ -100,6 +101,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
Expression e = calculationAtIndex(focusRow)->exactOutput();
if (additionalInfoType == Calculation::AdditionalInformationType::Complex) {
vc = &m_complexController;
+ } else if (additionalInfoType == Calculation::AdditionalInformationType::SecondDegree) {
+ vc = &m_secondDegreeController;
} else if (additionalInfoType == Calculation::AdditionalInformationType::Trigonometry) {
vc = &m_trigonometryController;
// Find which of the input or output is the cosine/sine
diff --git a/apps/calculation/history_controller.h b/apps/calculation/history_controller.h
index e289eb5fc43..8b7c3bf53ef 100644
--- a/apps/calculation/history_controller.h
+++ b/apps/calculation/history_controller.h
@@ -8,6 +8,7 @@
#include "additional_outputs/complex_list_controller.h"
#include "additional_outputs/integer_list_controller.h"
#include "additional_outputs/rational_list_controller.h"
+#include "additional_outputs/second_degree_list_controller.h"
#include "additional_outputs/trigonometry_list_controller.h"
#include "additional_outputs/unit_list_controller.h"
#include "additional_outputs/matrix_list_controller.h"
@@ -34,6 +35,7 @@ class HistoryController : public ViewController, public ListViewDataSource, publ
int typeAtLocation(int i, int j) override;
void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1) override;
void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override;
+ void reinsertTrash() { m_calculationStore->reinsertTrash(); }
private:
int storeIndex(int i) { return numberOfRows() - i - 1; }
Shared::ExpiringPointer calculationAtIndex(int i);
@@ -47,6 +49,7 @@ class HistoryController : public ViewController, public ListViewDataSource, publ
ComplexListController m_complexController;
IntegerListController m_integerController;
RationalListController m_rationalController;
+ SecondDegreeListController m_secondDegreeController;
TrigonometryListController m_trigonometryController;
UnitListController m_unitController;
MatrixListController m_matrixController;
diff --git a/apps/calculation/history_view_cell.cpp b/apps/calculation/history_view_cell.cpp
index 71799403c26..e30995750fb 100644
--- a/apps/calculation/history_view_cell.cpp
+++ b/apps/calculation/history_view_cell.cpp
@@ -81,7 +81,7 @@ void HistoryViewCell::reloadSubviewHighlight() {
m_ellipsis.setHighlighted(false);
if (isHighlighted()) {
if (m_dataSource->selectedSubviewType() == HistoryViewCellDataSource::SubviewType::Input) {
- m_inputView.setExpressionBackgroundColor(Palette::ListCellBackgroundSelected);
+ m_inputView.setExpressionBackgroundColor(Palette::Select);
} else if (m_dataSource->selectedSubviewType() == HistoryViewCellDataSource::SubviewType::Output) {
m_scrollableOutputView.evenOddCell()->setHighlighted(true);
} else {
diff --git a/apps/code/Makefile b/apps/code/Makefile
index 23b6a320780..af50725cd59 100644
--- a/apps/code/Makefile
+++ b/apps/code/Makefile
@@ -1,6 +1,8 @@
apps += Code::App
app_headers += apps/code/app.h
+SFLAGS += -DHAS_CODE
+
app_code_src = $(addprefix apps/code/,\
app.cpp \
console_controller.cpp \
diff --git a/apps/code/app.cpp b/apps/code/app.cpp
index 4db851b222b..8739030871c 100644
--- a/apps/code/app.cpp
+++ b/apps/code/app.cpp
@@ -3,6 +3,13 @@
#include
#include "helpers.h"
#include
+#include
+
+#if defined _FXCG || defined NSPIRE_NEWLIB
+extern "C" int calculator;
+extern "C" const int prizm_heap_size;
+extern "C" char prizm_heap[];
+#endif
namespace Code {
@@ -129,6 +136,16 @@ VariableBoxController * App::variableBoxForInputEventHandler(InputEventHandler *
}
bool App::textInputDidReceiveEvent(InputEventHandler * textInput, Ion::Events::Event event) {
+ if (event == Ion::Events::XNT) {
+ int bufferSize = CodePoint::MaxCodePointCharLength + 1;
+ char buffer[bufferSize];
+ bool shouldRemoveLastCharacter = false;
+ CodePoint codePoint = AppsContainer::sharedAppsContainer()->XNT('x', &shouldRemoveLastCharacter);
+ UTF8Decoder::CodePointToChars(codePoint, buffer, bufferSize);
+ buffer[UTF8Decoder::CharSizeOfCodePoint(codePoint)] = 0;
+ textInput->handleEventWithText(const_cast(buffer), false, false, shouldRemoveLastCharacter);
+ return true;
+ }
const char * pythonText = Helpers::PythonTextForEvent(event);
if (pythonText != nullptr) {
textInput->handleEventWithText(pythonText);
@@ -139,7 +156,17 @@ bool App::textInputDidReceiveEvent(InputEventHandler * textInput, Ion::Events::E
void App::initPythonWithUser(const void * pythonUser) {
if (!m_pythonUser) {
- MicroPython::init(m_pythonHeap, m_pythonHeap + k_pythonHeapSize);
+#if defined _FXCG || defined NSPIRE_NEWLIB
+ if (calculator == 1) { // fxcg50
+ MicroPython::init( (void *) 0x8c200000, (void *)(0x8c200000+ 0x2e0000));
+ } else if (calculator >= 1 && calculator <=4 ) {
+ MicroPython::init( prizm_heap, prizm_heap+prizm_heap_size);
+ } else {
+#endif
+ MicroPython::init(m_pythonHeap, m_pythonHeap + k_pythonHeapSize);
+#if defined _FXCG || defined NSPIRE_NEWLIB
+ }
+#endif
}
m_pythonUser = pythonUser;
}
diff --git a/apps/code/app.h b/apps/code/app.h
index 41f542eb4d4..67494d3f363 100644
--- a/apps/code/app.h
+++ b/apps/code/app.h
@@ -75,7 +75,7 @@ class App : public Shared::InputEventHandlerDelegateApp {
VariableBoxController * variableBoxController() { return &m_variableBoxController; }
- static constexpr int k_pythonHeapSize = 99000;
+ static constexpr int k_pythonHeapSize = 69500;
private:
/* Python delegate:
diff --git a/apps/code/base.universal.i18n b/apps/code/base.universal.i18n
index dbbf69f5a3b..57acbc2ec34 100644
--- a/apps/code/base.universal.i18n
+++ b/apps/code/base.universal.i18n
@@ -1,3 +1,2 @@
CodeAppCapital = "PYTHON"
ConsolePrompt = ">>> "
-ScriptParameters = "..."
diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n
index 3ec3691d972..b5a22857c9e 100644
--- a/apps/code/catalog.de.i18n
+++ b/apps/code/catalog.de.i18n
@@ -1,5 +1,11 @@
PythonPound = "Kommentar"
PythonPercent = "Modulo"
+PythonColon = "Doppelpunkt"
+PythonSemicon = "Semikolon"
+PythonExclamationMark = "Ausrufezeichen"
+PythonLessThan = "Kleiner als"
+PythonGreaterThan = "Größer als"
+PythonQuestionMark = "Fragezeichen"
Python1J = "Imaginäres i"
PythonLF = "Zeilenvorschub"
PythonTab = "Tabulator"
@@ -45,6 +51,7 @@ PythonCosh = "Hyperbolischer Kosinus"
PythonCount = "Zählt die Vorkommen von x"
PythonDegrees = "x von Bogenmaß in Grad umrechnen"
PythonDivMod = "Quotient und Rest"
+PythonDrawCircle = "Zeichne einen Kreis"
PythonDrawLine = "Eine Linie zeichnen"
PythonDrawString = "Text bei Pixel (x,y) darstellen"
PythonErf = "Fehlerfunktion"
@@ -52,13 +59,18 @@ PythonErfc = "Komplementäre Fehlerfunktion"
PythonEval = "Rückgabe ausgewerteter Ausdruck"
PythonExp = "Exponentialfunktion"
PythonExpm1 = "Berechne exp(x)-1"
+PythonFactorial = "Fakultät von x"
PythonFabs = "Absoluter Wert"
PythonFillRect = "Gefülltes Rechteck bei Pixel (x,y)"
+PythonFillCircle = "Füllt einen Kreis"
+PythonFillPolygon = "Füllt ein Polygon"
PythonFloat = "x in einen Fließkommawert umwandeln"
PythonFloor = "Abrunden"
PythonFmod = "a modulo b"
PythonFrExp = "Mantisse und Exponent von x: (m,e)"
PythonGamma = "Gamma-Funktion"
+PythonGetKeys = "Gedrückte Tasten erhalten"
+PythonGetPalette = "Themenpalette erhalten"
PythonGetPixel = "Farbe von Pixel (x,y) zurückgeben"
PythonGetrandbits = "Ganzzahl mit k Zufallsbits"
PythonGrid = "Sichtbarkeit des Gitters umschalten"
@@ -70,12 +82,22 @@ PythonImportKandinsky = "Kandinsky-Modul importieren"
PythonImportRandom = "Random-Modul importieren"
PythonImportMath = "Math-Modul importieren"
PythonImportMatplotlibPyplot = "Matplotlib.pyplot-Modul importieren"
+PythonImportNumpy = "Ulab.numpy-Modul importieren"
+PythonImportScipy = "Ulab.scipy-Modul importieren"
PythonImportOs = "OS-Modul importieren"
+PythonImportSys = "SYS-Modul importieren"
PythonOsUname = "Informationen über das System holen"
PythonOsGetlogin = "Benutzernamen holen"
PythonOsRemove = "Datei namens Dateiname entfernen"
PythonOsRename = "Datei umbenennen von Alt nach Neu"
PythonOsListdir = "Dateien im Speicher auflisten"
+PythonSysExit = "Terminate current program"
+PythonSysPrintexception = "Print exception"
+PythonSysByteorder = "The byte order of the system"
+PythonSysImplementation = "Information about Python"
+PythonSysModules = "Dictionary of loaded modules"
+PythonSysVersion = "Python language version (string)"
+PythonSysVersioninfo = "Python language version (tuple)"
PythonImportTime = "Time-Modul importieren"
PythonImportTurtle = "Turtle-Modul importieren"
PythonIndex = "Index des ersten x-Vorkommens"
@@ -87,7 +109,58 @@ PythonIsFinite = "Prüfen, ob x endlich ist"
PythonIsInfinite = "Prüfen, ob x unendlich ist"
PythonIsNaN = "Prüfen, ob x keine Zahl ist"
PythonIsKeyDown = "Wahr, wenn die Taste k gedrückt ist"
+PythonBattery = "Rückgabe der Batteriespannung"
+PythonBatteryLevel = "Gibt den Batteriestand zurück"
+PythonBatteryIscharging = "Gibt zurück, ob die Batterie geladen wird"
+PythonSetBrightness = "Helligkeitsstufe festlegen"
+PythonGetBrightness = "Helligkeitsstufe abrufen"
PythonKandinskyFunction = "Kandinsky-Modul Funktionspräfix"
+PythonKeyLeft = "LEFT ARROW key"
+PythonKeyUp = "UP ARROW key"
+PythonKeyDown = "DOWN ARROW key"
+PythonKeyRight = "RIGHT ARROW key"
+PythonKeyOk = "OK key"
+PythonKeyBack = "BACK key"
+PythonKeyHome = "HOME key"
+PythonKeyOnOff = "ON/OFF key"
+PythonKeyShift = "SHIFT key"
+PythonKeyAlpha = "ALPHA key"
+PythonKeyXnt = "X,N,T key"
+PythonKeyVar = "VAR key"
+PythonKeyToolbox = "TOOLBOX key"
+PythonKeyBackspace = "BACKSPACE key"
+PythonKeyExp = "EXPONENTIAL key"
+PythonKeyLn = "NATURAL LOGARITHM key"
+PythonKeyLog = "DECIMAL LOGARITHM key"
+PythonKeyImaginary = "IMAGINARY I key"
+PythonKeyComma = "COMMA key"
+PythonKeyPower = "POWER key"
+PythonKeySine = "SINE key"
+PythonKeyCosine = "COSINE key"
+PythonKeyTangent = "TANGENT key"
+PythonKeyPi = "PI key"
+PythonKeySqrt = "SQUARE ROOT key"
+PythonKeySquare = "SQUARE key"
+PythonKeySeven = "7 key"
+PythonKeyEight = "8 key"
+PythonKeyNine = "9 key"
+PythonKeyLeftParenthesis = "LEFT PARENTHESIS key"
+PythonKeyRightParenthesis = "RIGHT PARENTHESIS key"
+PythonKeyFour = "4 key"
+PythonKeyFive = "5 key"
+PythonKeySix = "6 key"
+PythonKeyMultiplication = "MULTIPLICATION key"
+PythonKeyDivision = "DIVISION key"
+PythonKeyOne = "1 key"
+PythonKeyTwo = "2 key"
+PythonKeyThree = "3 key"
+PythonKeyPlus = "PLUS key"
+PythonKeyMinus = "MINUS key"
+PythonKeyZero = "0 key"
+PythonKeyDot = "DOT key"
+PythonKeyEe = "10 POWER X key"
+PythonKeyAns = "ANS key"
+PythonKeyExe = "EXE key"
PythonLdexp = "Liefert x*(2**i), Inverse von frexp"
PythonLength = "Länge eines Objekts"
PythonLgamma = "Log-Gamma-Funktion"
@@ -100,6 +173,14 @@ PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Bruch- und Ganzzahl-Anteile von x"
PythonMonotonic = "Wert einer monotonen Uhr"
+PythonNumpyFunction = "numpy Modul-Präfix"
+PythonNumpyFftFunction = "numpy.fft Modul-Präfix"
+PythonNumpyLinalgFunction = "numpy.linalg Modul-Präfix"
+PythonScipyFunction = "scipy Modul-Präfix"
+PythonScipyLinalgFunction = "scipy.linalg Modul-Präfix"
+PythonScipyOptimizeFunction = "scipy.optimize Modul-Präfix"
+PythonScipySignalFunction = "scipy.signal Modul-Präfix"
+PythonScipySpecialFunction = "scipy.special Modul-Präfix"
PythonOct = "Ganzzahl in Oktal umwandeln"
PythonPhase = "Phase von z"
PythonPlot = "Plotten von y gegen x als Linien"
@@ -125,6 +206,12 @@ PythonShow = "Figur anzeigen"
PythonSin = "Sinus"
PythonSinh = "Hyperbolischer Sinus"
PythonSleep = "Ausführung aussetzen für t Sekunden"
+PythonLocalTime = "Zeit in Tupel umwandeln"
+PythonMktime = "Tupel in Zeit umwandeln"
+PythonTime = "Abrufen des aktuellen Zeitstempels"
+PythonSetLocaltime = "Zeit aus einem Tupel einstellen"
+PythonRTCmode = "Aktuellen RTC-Modus abrufen"
+PythonSetRTCmode = "RTC-Modus festlegen"
PythonSort = "Die Liste sortieren"
PythonSqrt = "Quadratwurzel"
PythonSum = "Summe der Elemente einer Liste"
@@ -151,14 +238,11 @@ PythonTurtlePosition = "Aktuelle (x,y) Position zurückgeben"
PythonTurtleReset = "Die Zeichnung zurücksetzen"
PythonTurtleRight = "Um ein Grad nach rechts drehen"
PythonTurtleSetheading = "Ausrichtung auf einen Grad setzen"
-PythonTurtleSetposition = "Den Igel auf Position setzen"
PythonTurtleShowturtle = "Den Igel anzeigen"
PythonTurtleSpeed = "Zeichengeschwindigkeit von 0 bis 10"
PythonTurtleWrite = "Einen Text anzeigen"
PythonUniform = "Fließkommazahl in [a,b]"
PythonImportTime = "Time-Modul importieren"
-PythonTimePrefix = "Zeitmodul-Funktionspräfix"
-PythonTimeSleep = "Warte für n Sekunden"
PythonMonotonic = "Monotone Zeit zurückgeben"
PythonFileOpen = "Öffnet eine Datei"
PythonFileSeekable = "Kann Datei durchsucht werden?"
@@ -176,3 +260,5 @@ PythonFileName = "Enthält den Namen der Datei"
PythonFileMode = "Enthält den Öffnungsmodus der Datei"
PythonFileReadable = "Kann Datei gelesen werden?"
PythonFileWritable = "Kann Datei geschrieben werden?"
+PythonImportUtils = "Importieren von ulab.utils"
+PythonUtilsFunction = "Funktionspräfix des utils-Moduls"
diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n
index e3b2d47787d..dd3936409d8 100644
--- a/apps/code/catalog.en.i18n
+++ b/apps/code/catalog.en.i18n
@@ -1,5 +1,11 @@
PythonPound = "Comment"
PythonPercent = "Modulo"
+PythonColon = "Colon"
+PythonSemicon = "Semicolon"
+PythonExclamationMark = "Exclamation mark"
+PythonLessThan = "Less than"
+PythonGreaterThan = "Greater than"
+PythonQuestionMark = "Question mark"
Python1J = "Imaginary i"
PythonLF = "Line feed"
PythonTab = "Tabulation"
@@ -45,6 +51,7 @@ PythonCosh = "Hyperbolic cosine"
PythonCount = "Count the occurrences of x"
PythonDegrees = "Convert x from radians to degrees"
PythonDivMod = "Quotient and remainder"
+PythonDrawCircle = "Draw a circle"
PythonDrawLine = "Draw a line"
PythonDrawString = "Display a text from pixel (x,y)"
PythonErf = "Error function"
@@ -52,13 +59,18 @@ PythonErfc = "Complementary error function"
PythonEval = "Return the evaluated expression"
PythonExp = "Exponential function"
PythonExpm1 = "Compute exp(x)-1"
+PythonFactorial = "Factorial of x"
PythonFabs = "Absolute value"
+PythonFillCircle = "Fill a circle"
+PythonFillPolygon = "Fill a polygon"
PythonFillRect = "Fill a rectangle at pixel (x,y)"
PythonFloat = "Convert x to a float"
PythonFloor = "Floor"
PythonFmod = "a modulo b"
PythonFrExp = "Mantissa and exponent of x: (m,e)"
PythonGamma = "Gamma function"
+PythonGetKeys = "Get keys pressed"
+PythonGetPalette = "Get theme palette"
PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits"
PythonGrid = "Toggle the visibility of the grid"
@@ -70,6 +82,8 @@ PythonImportKandinsky = "Import kandinsky module"
PythonImportRandom = "Import random module"
PythonImportMath = "Import math module"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
+PythonImportNumpy = "Import ulab.numpy module"
+PythonImportScipy = "Import ulab.scipy module"
PythonImportTime = "Import time module"
PythonImportTurtle = "Import turtle module"
PythonIndex = "Index of the first x occurrence"
@@ -80,8 +94,59 @@ PythonIonFunction = "ion module function prefix"
PythonIsFinite = "Check if x is finite"
PythonIsInfinite = "Check if x is infinity"
PythonIsKeyDown = "Return True if the k key is down"
+PythonBattery = "Return battery voltage"
+PythonBatteryLevel = "Return battery level"
+PythonBatteryIscharging = "Return if battery is charging"
+PythonSetBrightness = "Set brightness level"
+PythonGetBrightness = "Get brightness level"
PythonIsNaN = "Check if x is a NaN"
PythonKandinskyFunction = "kandinsky module function prefix"
+PythonKeyLeft = "LEFT ARROW key"
+PythonKeyUp = "UP ARROW key"
+PythonKeyDown = "DOWN ARROW key"
+PythonKeyRight = "RIGHT ARROW key"
+PythonKeyOk = "OK key"
+PythonKeyBack = "BACK key"
+PythonKeyHome = "HOME key"
+PythonKeyOnOff = "ON/OFF key"
+PythonKeyShift = "SHIFT key"
+PythonKeyAlpha = "ALPHA key"
+PythonKeyXnt = "X,N,T key"
+PythonKeyVar = "VAR key"
+PythonKeyToolbox = "TOOLBOX key"
+PythonKeyBackspace = "BACKSPACE key"
+PythonKeyExp = "EXPONENTIAL key"
+PythonKeyLn = "NATURAL LOGARITHM key"
+PythonKeyLog = "DECIMAL LOGARITHM key"
+PythonKeyImaginary = "IMAGINARY I key"
+PythonKeyComma = "COMMA key"
+PythonKeyPower = "POWER key"
+PythonKeySine = "SINE key"
+PythonKeyCosine = "COSINE key"
+PythonKeyTangent = "TANGENT key"
+PythonKeyPi = "PI key"
+PythonKeySqrt = "SQUARE ROOT key"
+PythonKeySquare = "SQUARE key"
+PythonKeySeven = "7 key"
+PythonKeyEight = "8 key"
+PythonKeyNine = "9 key"
+PythonKeyLeftParenthesis = "LEFT PARENTHESIS key"
+PythonKeyRightParenthesis = "RIGHT PARENTHESIS key"
+PythonKeyFour = "4 key"
+PythonKeyFive = "5 key"
+PythonKeySix = "6 key"
+PythonKeyMultiplication = "MULTIPLICATION key"
+PythonKeyDivision = "DIVISION key"
+PythonKeyOne = "1 key"
+PythonKeyTwo = "2 key"
+PythonKeyThree = "3 key"
+PythonKeyPlus = "PLUS key"
+PythonKeyMinus = "MINUS key"
+PythonKeyZero = "0 key"
+PythonKeyDot = "DOT key"
+PythonKeyEe = "10 POWER X key"
+PythonKeyAns = "ANS key"
+PythonKeyExe = "EXE key"
PythonLdexp = "Return x*(2**i), inverse of frexp"
PythonLength = "Length of an object"
PythonLgamma = "Log-gamma function"
@@ -94,6 +159,14 @@ PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractional and integer parts of x"
PythonMonotonic = "Value of a monotonic clock"
+PythonNumpyFunction = "numpy module prefix"
+PythonNumpyFftFunction = "numpy.fft module prefix"
+PythonNumpyLinalgFunction = "numpy.linalg module prefix"
+PythonScipyFunction = "scipy module prefix"
+PythonScipyLinalgFunction = "scipy.linalg module prefix"
+PythonScipyOptimizeFunction = "scipy.optimize module prefix"
+PythonScipySignalFunction = "scipy.signal module prefix"
+PythonScipySpecialFunction = "scipy.special module prefix"
PythonOct = "Convert integer to octal"
PythonPhase = "Phase of z"
PythonPlot = "Plot y versus x as lines"
@@ -119,6 +192,12 @@ PythonShow = "Display the figure"
PythonSin = "Sine"
PythonSinh = "Hyperbolic sine"
PythonSleep = "Suspend the execution for t seconds"
+PythonLocalTime = "Convert time into tuple"
+PythonMktime = "Convert tuple into time"
+PythonTime = "Get the current timestamp"
+PythonSetLocaltime = "Set time from a tuple"
+PythonRTCmode = "Get current RTC mode"
+PythonSetRTCmode = "Set RTC mode"
PythonSort = "Sort the list"
PythonSqrt = "Square root"
PythonSum = "Sum the items of a list"
@@ -145,20 +224,25 @@ PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtleReset = "Reset the drawing"
PythonTurtleRight = "Turn right by a degrees"
PythonTurtleSetheading = "Set the orientation to a degrees"
-PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Show the turtle"
PythonTurtleSpeed = "Drawing speed between 0 and 10"
PythonTurtleWrite = "Display a text"
PythonUniform = "Floating point number in [a,b]"
PythonImportTime = "Import time module"
PythonImportOs = "Import os module"
+PythonImportSys = "Import sys module"
PythonOsUname = "Get infos about the system"
PythonOsGetlogin = "Get username"
PythonOsRemove = "Remove file named filename"
PythonOsRename = "Rename file oldname to newname"
PythonOsListdir = "List files in memory"
-PythonTimePrefix = "time module function prefix"
-PythonTimeSleep = "Wait for n second"
+PythonSysExit = "Terminate current program"
+PythonSysPrintexception = "Print exception"
+PythonSysByteorder = "The byte order of the system"
+PythonSysImplementation = "Information about Python"
+PythonSysModules = "Dictionary of loaded modules"
+PythonSysVersion = "Python language version (string)"
+PythonSysVersioninfo = "Python language version (tuple)"
PythonMonotonic = "Return monotonic time"
PythonFileOpen = "Opens a file"
PythonFileSeekable = "Tells if seek can be used on a file"
@@ -176,3 +260,5 @@ PythonFileName = "Contains file's name"
PythonFileMode = "Contains file's open mode"
PythonFileReadable = "Tells if read can be used on a file"
PythonFileWritable = "Tells if write can be used on a file"
+PythonImportUtils = "Importing ulab.utils"
+PythonUtilsFunction = "utils module function prefix"
diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n
index 2dee2b928af..62d5bf2c991 100644
--- a/apps/code/catalog.es.i18n
+++ b/apps/code/catalog.es.i18n
@@ -1,5 +1,11 @@
PythonPound = "Comment"
PythonPercent = "Modulo"
+PythonColon = "Colon"
+PythonSemicon = "Semicolon"
+PythonExclamationMark = "Exclamation mark"
+PythonLessThan = "Less than"
+PythonGreaterThan = "Greater than"
+PythonQuestionMark = "Question mark"
Python1J = "Imaginary i"
PythonLF = "Line feed"
PythonTab = "Tabulation"
@@ -45,6 +51,7 @@ PythonCosh = "Hyperbolic cosine"
PythonCount = "Count the occurrences of x"
PythonDegrees = "Convert x from radians to degrees"
PythonDivMod = "Quotient and remainder"
+PythonDrawCircle = "Draw a circle"
PythonDrawLine = "Draw a line"
PythonDrawString = "Display a text from pixel (x,y)"
PythonErf = "Error function"
@@ -52,13 +59,18 @@ PythonErfc = "Complementary error function"
PythonEval = "Return the evaluated expression"
PythonExp = "Exponential function"
PythonExpm1 = "Compute exp(x)-1"
+PythonFactorial = "factorial de x"
PythonFabs = "Absolute value"
+PythonFillCircle = "Fill a circle"
+PythonFillPolygon = "Fill a polygon"
PythonFillRect = "Fill a rectangle at pixel (x,y)"
PythonFloat = "Convert x to a float"
PythonFloor = "Floor"
PythonFmod = "a modulo b"
PythonFrExp = "Mantissa and exponent of x: (m,e)"
PythonGamma = "Gamma function"
+PythonGetKeys = "Obtener teclas presionadas"
+PythonGetPalette = "Get theme palette"
PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits"
PythonGrid = "Toggle the visibility of the grid"
@@ -70,6 +82,8 @@ PythonImportKandinsky = "Import kandinsky module"
PythonImportRandom = "Import random module"
PythonImportMath = "Import math module"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
+PythonImportNumpy = "Import ulab.numpy module"
+PythonImportScipy = "Import ulab.scipy module"
PythonImportTime = "Import time module"
PythonImportTurtle = "Import turtle module"
PythonIndex = "Index of the first x occurrence"
@@ -80,8 +94,59 @@ PythonIonFunction = "ion module function prefix"
PythonIsFinite = "Check if x is finite"
PythonIsInfinite = "Check if x is infinity"
PythonIsKeyDown = "Return True if the k key is down"
+PythonBattery = "Rückgabe der Batteriespannung"
+PythonBatteryLevel = "Gibt den Batteriestand zurück"
+PythonBatteryIscharging = "Gibt zurück, ob die Batterie geladen wird"
+PythonSetBrightness = "Establecer nivel de brillo"
+PythonGetBrightness = "Obtener nivel de brillo"
PythonIsNaN = "Check if x is a NaN"
PythonKandinskyFunction = "kandinsky module function prefix"
+PythonKeyLeft = "LEFT ARROW key"
+PythonKeyUp = "UP ARROW key"
+PythonKeyDown = "DOWN ARROW key"
+PythonKeyRight = "RIGHT ARROW key"
+PythonKeyOk = "OK key"
+PythonKeyBack = "BACK key"
+PythonKeyHome = "HOME key"
+PythonKeyOnOff = "ON/OFF key"
+PythonKeyShift = "SHIFT key"
+PythonKeyAlpha = "ALPHA key"
+PythonKeyXnt = "X,N,T key"
+PythonKeyVar = "VAR key"
+PythonKeyToolbox = "TOOLBOX key"
+PythonKeyBackspace = "BACKSPACE key"
+PythonKeyExp = "EXPONENTIAL key"
+PythonKeyLn = "NATURAL LOGARITHM key"
+PythonKeyLog = "DECIMAL LOGARITHM key"
+PythonKeyImaginary = "IMAGINARY I key"
+PythonKeyComma = "COMMA key"
+PythonKeyPower = "POWER key"
+PythonKeySine = "SINE key"
+PythonKeyCosine = "COSINE key"
+PythonKeyTangent = "TANGENT key"
+PythonKeyPi = "PI key"
+PythonKeySqrt = "SQUARE ROOT key"
+PythonKeySquare = "SQUARE key"
+PythonKeySeven = "7 key"
+PythonKeyEight = "8 key"
+PythonKeyNine = "9 key"
+PythonKeyLeftParenthesis = "LEFT PARENTHESIS key"
+PythonKeyRightParenthesis = "RIGHT PARENTHESIS key"
+PythonKeyFour = "4 key"
+PythonKeyFive = "5 key"
+PythonKeySix = "6 key"
+PythonKeyMultiplication = "MULTIPLICATION key"
+PythonKeyDivision = "DIVISION key"
+PythonKeyOne = "1 key"
+PythonKeyTwo = "2 key"
+PythonKeyThree = "3 key"
+PythonKeyPlus = "PLUS key"
+PythonKeyMinus = "MINUS key"
+PythonKeyZero = "0 key"
+PythonKeyDot = "DOT key"
+PythonKeyEe = "10 POWER X key"
+PythonKeyAns = "ANS key"
+PythonKeyExe = "EXE key"
PythonLdexp = "Return x*(2**i), inverse of frexp"
PythonLength = "Length of an object"
PythonLgamma = "Log-gamma function"
@@ -94,6 +159,14 @@ PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractional and integer parts of x"
PythonMonotonic = "Value of a monotonic clock"
+PythonNumpyFunction = "numpy module prefix"
+PythonNumpyFftFunction = "numpy.fft module prefix"
+PythonNumpyLinalgFunction = "numpy.linalg module prefix"
+PythonScipyFunction = "scipy module prefix"
+PythonScipyLinalgFunction = "scipy.linalg module prefix"
+PythonScipyOptimizeFunction = "scipy.optimize module prefix"
+PythonScipySignalFunction = "scipy.signal module prefix"
+PythonScipySpecialFunction = "scipy.special module prefix"
PythonOct = "Convert integer to octal"
PythonPhase = "Phase of z"
PythonPlot = "Plot y versus x as lines"
@@ -119,6 +192,12 @@ PythonShow = "Display the figure"
PythonSin = "Sine"
PythonSinh = "Hyperbolic sine"
PythonSleep = "Suspend the execution for t seconds"
+PythonLocalTime = "Convertir el tiempo en tupla"
+PythonMktime = "Convertir tupla en tiempo"
+PythonTime = "Obtener la marca de tiempo actual"
+PythonSetLocaltime = "Establecer tiempo desde una tupla"
+PythonRTCmode = "Obtener el modo RTC actual"
+PythonSetRTCmode = "Establecer modo RTC"
PythonSort = "Sort the list"
PythonSqrt = "Square root"
PythonSum = "Sum the items of a list"
@@ -145,20 +224,25 @@ PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtleReset = "Reset the drawing"
PythonTurtleRight = "Turn right by a degrees"
PythonTurtleSetheading = "Set the orientation to a degrees"
-PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Show the turtle"
PythonTurtleSpeed = "Drawing speed between 0 and 10"
PythonTurtleWrite = "Display a text"
PythonUniform = "Floating point number in [a,b]"
PythonImportTime = "Import time module"
PythonImportOs = "Import os module"
+PythonImportSys = "Import sys module"
PythonOsUname = " Información del sistema "
PythonOsGetlogin = "Get username"
PythonOsRemove = "Eliminar un archivo"
PythonOsRename = "Renombrar archivo"
PythonOsListdir = "Archivos de la lista"
-PythonTimePrefix = "time module function prefix"
-PythonTimeSleep = "Esperar n segundos"
+PythonSysExit = "Terminate current program"
+PythonSysPrintexception = "Print exception"
+PythonSysByteorder = "The byte order of the system"
+PythonSysImplementation = "Information about Python"
+PythonSysModules = "Dictionary of loaded modules"
+PythonSysVersion = "Python language version (string)"
+PythonSysVersioninfo = "Python language version (tuple)"
PythonMonotonic = "Tiempo monótono de retorno"
PythonFileOpen = "Opens a file"
PythonFileSeekable = "Tells if seek can be used on a file"
@@ -176,3 +260,5 @@ PythonFileName = "Contains file's name"
PythonFileMode = "Contains file's open mode"
PythonFileReadable = "Tells if read can be used on a file"
PythonFileWritable = "Tells if write can be used on a file"
+PythonImportUtils = "Importando ulab.utils"
+PythonUtilsFunction = "prefijo de función del módulo utils"
diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n
index 4ac2560c962..3185c5ce5a8 100644
--- a/apps/code/catalog.fr.i18n
+++ b/apps/code/catalog.fr.i18n
@@ -1,5 +1,11 @@
PythonPound = "Commentaire"
PythonPercent = "Modulo"
+PythonColon = "Deux-points"
+PythonSemicon = "Point-virgule"
+PythonExclamationMark = "Point d'exclamation"
+PythonLessThan = "Inférieur à"
+PythonGreaterThan = "Supérieur à"
+PythonQuestionMark = "Point d'interrogation"
Python1J = "i complexe"
PythonLF = "Saut à la ligne"
PythonTab = "Tabulation"
@@ -45,6 +51,7 @@ PythonCosh = "Cosinus hyperbolique"
PythonCount = "Compte les occurrences de x"
PythonDegrees = "Conversion de radians en degrés"
PythonDivMod = "Quotient et reste"
+PythonDrawCircle = "Trace un cercle"
PythonDrawLine = "Trace une ligne"
PythonDrawString = "Affiche un texte au pixel (x,y)"
PythonErf = "Fonction d'erreur"
@@ -52,13 +59,18 @@ PythonErfc = "Fonction d'erreur complémentaire"
PythonEval = "Evalue l'expression en argument "
PythonExp = "Fonction exponentielle"
PythonExpm1 = "Calcul de exp(x)-1"
+PythonFactorial = "Factorielle de x"
PythonFabs = "Valeur absolue"
+PythonFillCircle = "Remplit un cercle"
+PythonFillPolygon = "Remplit un polygone"
PythonFillRect = "Remplit un rectangle"
PythonFloat = "Conversion en flottant"
PythonFloor = "Partie entière"
PythonFmod = "a modulo b"
PythonFrExp = "Mantisse et exposant de x : (m,e)"
PythonGamma = "Fonction gamma"
+PythonGetKeys = "Obtenir les touches pressées"
+PythonGetPalette = "Obtient la palette du thème"
PythonGetPixel = "Renvoie la couleur du pixel (x,y)"
PythonGetrandbits = "Nombre aléatoire sur k bits"
PythonGrid = "Affiche ou masque la grille"
@@ -70,6 +82,9 @@ PythonImportKandinsky = "Importation du module kandinsky"
PythonImportRandom = "Importation du module random"
PythonImportMath = "Importation du module math"
PythonImportMatplotlibPyplot = "Importation de matplotlib.pyplot"
+PythonImportNumpy = "Importation de ulab.numpy"
+PythonImportScipy = "Importation de ulab.scipy"
+PythonImportUtils = "Importation de ulab.utils"
PythonImportTurtle = "Importation du module turtle"
PythonImportTime = "Importation du module time"
PythonIndex = "Indice première occurrence de x"
@@ -80,8 +95,59 @@ PythonIonFunction = "Préfixe fonction module ion"
PythonIsFinite = "Teste si x est fini"
PythonIsInfinite = "Teste si x est infini"
PythonIsKeyDown = "Renvoie True si touche k enfoncée"
+PythonBattery = "Renvoie le voltage de la batterie"
+PythonBatteryLevel = "Renvoie le niveau de la batterie"
+PythonBatteryIscharging = "Chargement en cours"
+PythonSetBrightness = "Définir le niveau de luminosité"
+PythonGetBrightness = "Obtenir le niveau de luminosité"
PythonIsNaN = "Teste si x est NaN"
PythonKandinskyFunction = "Préfixe fonction module kandinsky"
+PythonKeyLeft = "Touche FLECHE GAUCHE"
+PythonKeyUp = "Touche FLECHE HAUT"
+PythonKeyDown = "Touche FLECHE BAS"
+PythonKeyRight = "Touche FLECHE DROITE"
+PythonKeyOk = "Touche OK"
+PythonKeyBack = "Touche RETOUR"
+PythonKeyHome = "Touche HOME"
+PythonKeyOnOff = "Touche ON/OFF"
+PythonKeyShift = "Touche SHIFT"
+PythonKeyAlpha = "Touche ALPHA"
+PythonKeyXnt = "Touche X,N,T"
+PythonKeyVar = "Touche VAR"
+PythonKeyToolbox = "Touche BOITE A OUTILS"
+PythonKeyBackspace = "Touche EFFACER"
+PythonKeyExp = "Touche EXPONENTIELLE"
+PythonKeyLn = "Touche LOGARITHME NEPERIEN"
+PythonKeyLog = "Touche LOGARITHME DECIMAL"
+PythonKeyImaginary = "Touche I IMAGINAIRE"
+PythonKeyComma = "Touche VIRGULE"
+PythonKeyPower = "Touche PUISSANCE"
+PythonKeySine = "Touche SINUS"
+PythonKeyCosine = "Touche COSINUS"
+PythonKeyTangent = "Touche TANGENTE"
+PythonKeyPi = "Touche PI"
+PythonKeySqrt = "Touche RACINE CARREE"
+PythonKeySquare = "Touche CARRE"
+PythonKeySeven = "Touche 7"
+PythonKeyEight = "Touche 8"
+PythonKeyNine = "Touche 9"
+PythonKeyLeftParenthesis = "Touche PARENTHESE GAUCHE"
+PythonKeyRightParenthesis = "Touche PARENTHESE DROITE"
+PythonKeyFour = "Touche 4"
+PythonKeyFive = "Touche 5"
+PythonKeySix = "Touche 6"
+PythonKeyMultiplication = "Touche MULTIPLICATION"
+PythonKeyDivision = "Touche DIVISION"
+PythonKeyOne = "Touche 1"
+PythonKeyTwo = "Touche 2"
+PythonKeyThree = "Touche 3"
+PythonKeyPlus = "Touche PLUS"
+PythonKeyMinus = "Touche MOINS"
+PythonKeyZero = "Touche 0"
+PythonKeyDot = "Touche POINT"
+PythonKeyEe = "Touche 10 PUISSANCE X"
+PythonKeyAns = "Touche ANS"
+PythonKeyExe = "Touche EXE"
PythonLdexp = "Inverse de frexp : x*(2**i)"
PythonLength = "Longueur d'un objet"
PythonLgamma = "Logarithme de la fonction gamma"
@@ -94,6 +160,15 @@ PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Parties fractionnaire et entière"
PythonMonotonic = "Renvoie la valeur de l'horloge"
+PythonNumpyFunction = "Préfixe fonction du module numpy"
+PythonNumpyFftFunction = "Préfixe fonction du module numpy.fft"
+PythonNumpyLinalgFunction = "Préfixe fonction du module numpy.linalg"
+PythonScipyFunction = "Préfixe fonction du module scipy"
+PythonScipyLinalgFunction = "Préfixe fonction du module scipy.linalg"
+PythonScipyOptimizeFunction = "Préfixe fonction du module scipy.optimize"
+PythonScipySignalFunction = "Préfixe fonction du module scipy.signal"
+PythonScipySpecialFunction = "Préfixe fonction du module scipy.special"
+PythonUtilsFunction = "Préfixe fonction du module utils"
PythonOct = "Conversion en octal"
PythonPhase = "Argument de z"
PythonPlot = "Trace y en fonction de x"
@@ -109,7 +184,7 @@ PythonRandrange = "Nombre dans range(start,stop)"
PythonRangeStartStop = "Liste de start à stop-1"
PythonRangeStop = "Liste de 0 à stop-1"
PythonRect = "Conversion en algébrique"
-PythonRemove = "Supprime le premier x de la liste"
+PythonRemove = "Supprime le premier x de la liste"
PythonReverse = "Inverse les éléments de la liste"
PythonRound = "Arrondi à n décimales"
PythonScatter = "Nuage des points (x,y)"
@@ -119,6 +194,12 @@ PythonShow = "Affiche la figure"
PythonSin = "Sinus"
PythonSinh = "Sinus hyperbolique"
PythonSleep = "Suspend l'exécution t secondes"
+PythonLocalTime = "Convertir le temps en tuple"
+PythonMktime = "Convertir le tuple en temps"
+PythonTime = "Obtenir l'horodatage actuel"
+PythonSetLocaltime = "Définir l'heure à partir d'un tuple"
+PythonRTCmode = "Obtenir le mode RTC actuel"
+PythonSetRTCmode = "Définir le mode RTC"
PythonSort = "Trie la liste"
PythonSqrt = "Racine carrée"
PythonSum = "Somme des éléments de la liste"
@@ -145,20 +226,25 @@ PythonTurtlePosition = "Renvoie la position (x,y)"
PythonTurtleReset = "Réinitialise le dessin"
PythonTurtleRight = "Pivote de a degrés vers la droite"
PythonTurtleSetheading = "Met un cap de a degrés"
-PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Affiche la tortue"
PythonTurtleSpeed = "Vitesse du tracé entre 0 et 10"
PythonTurtleWrite = "Affiche un texte"
PythonUniform = "Nombre décimal dans [a,b]"
PythonImportTime = "Importation du module temps"
PythonImportOs = "Importation du module os"
+PythonImportSys = "Importation du module sys"
PythonOsUname = "Donne des infos sur le système"
PythonOsGetlogin = "Donne le nom d'utilisateur"
PythonOsRemove = "Supprime le fichier nommé filename"
PythonOsRename = "Renomme oldname en newname"
PythonOsListdir = "Liste les fichiers"
-PythonTimePrefix = "Préfixe fonction du module temps"
-PythonTimeSleep = "Attendre n secondes"
+PythonSysExit = "Termine le programme"
+PythonSysPrintexception = "Imprime une exception"
+PythonSysByteorder = "L'ordre des octets du système"
+PythonSysImplementation = "Information sur Python"
+PythonSysModules = "Dictionnaire des modules chargés"
+PythonSysVersion = "Version du langage Python (string)"
+PythonSysVersioninfo = "Version du langage Python (tuple)"
PythonMonotonic = "Retourne le temps monotone"
PythonFileOpen = "Ouvre un fichier"
PythonFileSeekable = "Indique si seek peut être utilisé"
diff --git a/apps/code/catalog.hu.i18n b/apps/code/catalog.hu.i18n
index 6959839aa06..7dd162659e9 100644
--- a/apps/code/catalog.hu.i18n
+++ b/apps/code/catalog.hu.i18n
@@ -1,178 +1,264 @@
-PythonPound = "Megjegyzés"
-PythonPercent = "Modulo"
-Python1J = "Képzeletbeli i"
-PythonLF = "Enter"
-PythonTab = "Táblázat"
-PythonAmpersand = "Logikus és"
-PythonSymbolExp = "logikus exkluzív vagy pedig"
-PythonVerticalBar = "logikus vagy pedig"
-PythonImag = "z képzeletbeli része"
-PythonReal = "z valódi része"
-PythonSingleQuote = "apostróf"
-PythonAbs = "Abszolút érték/nagyság"
-PythonAcos = "Ív (arc) koszinusz"
-PythonAcosh = "Hiperbolikus arc koszinusz"
-PythonAppend = "Lista végére hozzáadni x-et"
-PythonArrow = "(x,y) nyíla (x+dx,y+dy) nyílához"
-PythonAsin = "Ív (arc) szinusz"
-PythonAsinh = "Hiperbolikus ív (arc) szinusz"
-PythonAtan = "Ív (arc) érintö (tan)"
-PythonAtan2 = "atan(y/x) sámolása"
-PythonAtanh = "Hiperbolikus ív (arc) érintö (atan)"
-PythonAxis = "Tengelyeket (xmin,xmax,ymin,ymax)-ra állitani"
-PythonBar = "Az x lista oszlopdiagramja"
-PythonBin = "Egész szám konvertálása binárisra"
-PythonCeil = "Mennyezet"
-PythonChoice = "Véletlenszerü szám a listában"
-PythonClear = "A lista ürítése"
-PythonCmathFunction = "cmath modul funkció elötag"
-PythonColor = "Rgb (pzk) szín allítása"
-PythonColorBlack = "Fekete szín"
-PythonColorBlue = "Kék szín"
-PythonColorBrown = "Barna szín"
-PythonColorGreen = "Zöld szín"
-PythonColorGray = "Szürke szín"
-PythonColorOrange = "Narancssárga szín"
-PythonColorPink = "Rózsaszín szín"
-PythonColorPurple = "Lila szín"
-PythonColorRed = "Piros szín"
-PythonColorWhite = "Fehér szín"
-PythonColorYellow = "Sárga szín"
-PythonComplex = "A + ib visszaadása"
-PythonCopySign = "X visszaadása y jelével"
-PythonCos = "Koszinusz"
-PythonCosh = "Hiperbolikus koszinusz"
-PythonCount = "Számolja az x elöfordulását"
-PythonDegrees = "x konvertálása radiánokrol fokokra"
-PythonDivMod = "Hányados és maradék"
-PythonDrawLine = "Húzzon egy vonalat "
-PythonDrawString = "Szöveg megjelenítése (x, y)-en"
-PythonErf = "Hiba funkció"
-PythonErfc = "Kiegészítö hiba funkció"
-PythonEval = "Visszaadja az értékelt kifejezést"
-PythonExp = "Exponenciális függvény"
-PythonExpm1 = "exp(x)-1 sámitása"
-PythonFabs = "Abszolút érték"
-PythonFillRect = "Téglalap töltése"
-PythonFloat = "Konvertálása tizedes számra"
-PythonFloor = "Egész része"
-PythonFmod = "a modulo b"
-PythonFrExp = "X mantissája és kiállítója"
-PythonGamma = "Gamma funkció"
-PythonGetPixel = "Visszatéríti (x,y) színét"
-PythonGetrandbits = "Váletlenszám visszatérítése k biten"
-PythonGrid = "Rács megjelenítése/elrejtése"
-PythonHex = "Decimális szám konvertálása hexadecimális számra"
-PythonHist = "x hisztográmiája"
-PythonImportCmath = "cmath modul importálása"
-PythonImportIon = "Ion modul importálása"
-PythonImportKandinsky = "Kandinsky modul importálása"
-PythonImportRandom = "Véletlenszerü modul importálása"
-PythonImportMath = "math modul importálása"
-PythonImportMatplotlibPyplot = "matplotlib.pyplot modul importálása"
-PythonImportTurtle = "turtle modul importálása"
-PythonImportTime = "time modul importálása"
-PythonIndex = "Az elsö x esemény indexe"
-PythonInput = "Irjon egy értéket (számot)"
-PythonInsert = "x-et i. pozícióra helyezze a listában"
-PythonInt = "egész számra konvertálás"
-PythonIonFunction = "ion modul funkció elötag"
-PythonIsFinite = "x véges-e"
-PythonIsInfinite = "x végtelen-e"
-PythonIsKeyDown = "True-t válaszol ha a k gomb le van nyomva"
-PythonIsNaN = "Ellenörizze hogy x nem NaN"
-PythonKandinskyFunction = "kandinsky modul funkció elötag"
-PythonLdexp = "frexp ellentéte : x*(2**i)"
-PythonLength = "Egy targy hossza"
-PythonLgamma = "Gamma funkció logaritmusa"
-PythonLog = "a alapú logaritmus"
-PythonLog10 = "Decimális logaritmus"
-PythonLog2 = "Bináris logaritmus"
-PythonMathFunction = "math modul funkció elötag"
-PythonMatplotlibPyplotFunction = "matplotlib.pyplot elötag"
-PythonMax = "Maximum"
-PythonMin = "Minimum"
-PythonModf = "x-nek tört és egész részei"
-PythonMonotonic = "Az óra értékét adja vissza"
-PythonOct = "Decimális szám konvertálása octális számra"
-PythonPhase = "z fázisa"
-PythonPlot = "y-t jelöli x függvényében"
-PythonPolar = "Verctorizálni"
-PythonPop = "Az utolsó elemet el törölni"
-PythonPower = "x y. kitevö"
-PythonPrint = "Ki irni a elemeket"
-PythonRadians = "Fokról radiánra konvertálni"
-PythonRandint = "Véletlen egész szám [a;b] -ban"
-PythonRandom = "Decimális szám [0;1] -ban"
-PythonRandomFunction = "random modul funkció elötag"
-PythonRandrange = "Véletlen szám range(start,stop)-ban"
-PythonRangeStartStop = "start-tol stop-ig listája"
-PythonRangeStop = "0 tol stop-ig lista"
-PythonRect = "Algebrai számra konvertálni"
-PythonRemove = "Elsö x elöfordulását törolni"
-PythonReverse = "A lista elemeit megfordítani (másik irány)"
-PythonRound = "N számjegyre kerekítni"
-PythonScatter = "(x,y) halmaza"
-PythonSeed = "Inicializálni a véletlenszám-választót"
-PythonSetPixel = "Az (x,y) pixel-t ki szinezni"
-PythonShow = "Mutassa az ábrát"
-PythonSin = "Szinusz"
-PythonSinh = "Hiperbolikus szinusz"
-PythonSleep = "t másodpercre meg állitani a programmot"
-PythonSort = "A listát rendezni"
-PythonSqrt = "Négyzetgyök"
-PythonSum = "Összeadni a lista elemeit"
-PythonTan = "Érintö (tan)"
-PythonTanh = "Hiperbolikus érintö (tan)"
-PythonText = "(x,y) nél egy szöveget irni"
-PythonTimeFunction = "time funkció elötag"
-PythonTrunc = "Egész csonka (?)"
-PythonTurtleBackward = "x pixelt hátra"
-PythonTurtleCircle = "r pixel sugarú kört rajzolni"
-PythonTurtleColor = "Toll szinét beállitani"
-PythonTurtleColorMode = "Szin módot 1.0-ra vagy 255-ra állitani"
-PythonTurtleForward = "x pixelt elölre"
-PythonTurtleFunction = "turtle modul funkció elötag"
-PythonTurtleGoto = "Menjen a (x,y) koordinátákra"
-PythonTurtleHeading = "Visszaadja az aktuális irányt"
-PythonTurtleHideturtle = "A teknös elrejtése"
-PythonTurtleIsdown = "True-t válaszol ha a toll irás pozícióban van"
-PythonTurtleLeft = "a fokkot forduljon balra"
-PythonTurtlePendown = "Húzza le a tollat"
-PythonTurtlePensize = "Állítsa a vonalvastagságot x pixelre"
-PythonTurtlePenup = "Húzza fel a tollat"
-PythonTurtlePosition = "Az aktuális (x,y) pozíciót visszaadása"
-PythonTurtleReset = "Visszaállitani a rajzot (torléssel)"
-PythonTurtleRight = "a fokkot forduljon jobbra"
-PythonTurtleSetheading = "a fokokra állítja be az irányt"
-PythonTurtleSetposition = "A teknös pozicioját allitja"
-PythonTurtleShowturtle = "A teknöst meg mutatni"
-PythonTurtleSpeed = "Rajzolási sebesség 0 és 10 között"
-PythonTurtleWrite = "Szöveg irás"
-PythonUniform = "Lebegöpontos szám [a,b] -ban"
-PythonImportTime = "time modul importálása"
-PythonTimePrefix = "time funkció elötag"
-PythonTimeSleep = "n másodpercet várni"
-PythonMonotonic = "Meg fordítani a monoton idö"
-PythonFileOpen = "Fájl megnyitása"
-PythonFileSeekable = "Seek-et lehete használni"
-PythonFileSeek = "A kurzort áthelyezni"
-PythonFileTell = "Visszaadja a kurzor helye"
-PythonFileClose = "Bezárni egy fájlt"
-PythonFileClosed = "True ha a fájl bezárva"
-PythonFileRead = "Olvas 16 bájtig"
-PythonFileWrite = "b-t irjon a fájlba"
-PythonFileReadline = "Olvas egy sort vagy 16 bájtig"
-PythonFileReadlines = "Olvas több sort"
-PythonFileTruncate = "A fájl átméretezése"
-PythonFileWritelines = "Irjon több sort"
-PythonFileName = "A fájl neve"
-PythonFileMode = "A fájl nyitott módja"
-PythonFileReadable = "read-et lehete használni"
-PythonFileWritable = "write-ot lehete használni"
-PythonImportOs = "os modul importálása"
-PythonOsUname = "Rendszer informaciók"
-PythonOsGetlogin = "Get username"
-PythonOsRemove = "Fájl törlése"
-PythonOsRename = "Fájl átnevezése"
-PythonOsListdir = "Fájlok listája"
+PythonPound = "Megjegyzés"
+PythonPercent = "Modulo"
+PythonColon = "Kettőspont"
+PythonSemicon = "Pontosvessző"
+PythonExclamationMark = "Felkiáltójel"
+PythonLessThan = "Kisebb mint"
+PythonGreaterThan = "Nagyobb mint"
+PythonQuestionMark = "Kérdőjel"
+Python1J = "Képzeletbeli i"
+PythonLF = "Enter"
+PythonTab = "Táblázat"
+PythonAmpersand = "Logikus és"
+PythonSymbolExp = "logikus exkluzív vagy pedig"
+PythonVerticalBar = "logikus vagy pedig"
+PythonImag = "z képzeletbeli része"
+PythonReal = "z valódi része"
+PythonSingleQuote = "apostróf"
+PythonAbs = "Abszolút érték/nagyság"
+PythonAcos = "Ív (arc) koszinusz"
+PythonAcosh = "Hiperbolikus arc koszinusz"
+PythonAppend = "Lista végére hozzáadni x-et"
+PythonArrow = "(x,y) nyíla (x+dx,y+dy) nyílához"
+PythonAsin = "Ív (arc) szinusz"
+PythonAsinh = "Hiperbolikus ív (arc) szinusz"
+PythonAtan = "Ív (arc) érintö (tan)"
+PythonAtan2 = "atan(y/x) sámolása"
+PythonAtanh = "Hiperbolikus ív (arc) érintö (atan)"
+PythonAxis = "Tengelyeket (xmin,xmax,ymin,ymax)-ra állitani"
+PythonBar = "Az x lista oszlopdiagramja"
+PythonBin = "Egész szám konvertálása binárisra"
+PythonCeil = "Mennyezet"
+PythonChoice = "Véletlenszerü szám a listában"
+PythonClear = "A lista ürítése"
+PythonCmathFunction = "cmath modul funkció elötag"
+PythonColor = "Rgb (pzk) szín allítása"
+PythonColorBlack = "Fekete szín"
+PythonColorBlue = "Kék szín"
+PythonColorBrown = "Barna szín"
+PythonColorGreen = "Zöld szín"
+PythonColorGray = "Szürke szín"
+PythonColorOrange = "Narancssárga szín"
+PythonColorPink = "Rózsaszín szín"
+PythonColorPurple = "Lila szín"
+PythonColorRed = "Piros szín"
+PythonColorWhite = "Fehér szín"
+PythonColorYellow = "Sárga szín"
+PythonComplex = "A + ib visszaadása"
+PythonCopySign = "X visszaadása y jelével"
+PythonCos = "Koszinusz"
+PythonCosh = "Hiperbolikus koszinusz"
+PythonCount = "Számolja az x elöfordulását"
+PythonDegrees = "x konvertálása radiánokrol fokokra"
+PythonDivMod = "Hányados és maradék"
+PythonDrawCircle = "Rajzolj egy kört"
+PythonDrawLine = "Húzzon egy vonalat "
+PythonDrawString = "Szöveg megjelenítése (x, y)-en"
+PythonErf = "Hiba funkció"
+PythonErfc = "Kiegészítö hiba funkció"
+PythonEval = "Visszaadja az értékelt kifejezést"
+PythonExp = "Exponenciális függvény"
+PythonExpm1 = "exp(x)-1 sámitása"
+PythonFactorial = "x faktorál"
+PythonFabs = "Abszolút érték"
+PythonFillRect = "Téglalap töltése"
+PythonFillCircle = "Kitölti a kört"
+PythonFillPolygon = "Kitölti a poligont"
+PythonFloat = "Konvertálása tizedes számra"
+PythonFloor = "Egész része"
+PythonFmod = "a modulo b"
+PythonFrExp = "X mantissája és kiállítója"
+PythonGamma = "Gamma funkció"
+PythonGetKeys = "Billentyűk lenyomva"
+PythonGetPalette = "Téma paletta beszerzése"
+PythonGetPixel = "Visszatéríti (x,y) színét"
+PythonGetrandbits = "Váletlenszám visszatérítése k biten"
+PythonGrid = "Rács megjelenítése/elrejtése"
+PythonHex = "Decimális szám konvertálása hexadecimális számra"
+PythonHist = "x hisztográmiája"
+PythonImportCmath = "cmath modul importálása"
+PythonImportIon = "Ion modul importálása"
+PythonImportKandinsky = "Kandinsky modul importálása"
+PythonImportRandom = "Véletlenszerü modul importálása"
+PythonImportMath = "math modul importálása"
+PythonImportMatplotlibPyplot = "matplotlib.pyplot modul importálása"
+PythonImportNumpy = "ulab.numpy modul importálása"
+PythonImportScipy = "ulab.scipy modul importálása"
+PythonImportTurtle = "turtle modul importálása"
+PythonImportTime = "time modul importálása"
+PythonIndex = "Az elsö x esemény indexe"
+PythonInput = "Irjon egy értéket (számot)"
+PythonInsert = "x-et i. pozícióra helyezze a listában"
+PythonInt = "egész számra konvertálás"
+PythonIonFunction = "ion modul funkció elötag"
+PythonIsFinite = "x véges-e"
+PythonIsInfinite = "x végtelen-e"
+PythonIsKeyDown = "True-t válaszol ha a k gomb le van nyomva"
+PythonBattery = "Az akkumulátor feszültségének visszaadása"
+PythonBatteryLevel = "Az akkumulátor töltöttségi szintjének visszaadása"
+PythonBatteryIscharging = "Visszaadja, ha az akkumulátor töltődik"
+PythonSetBrightness = "Fényerőszint beállítása"
+PythonGetBrightness = "Get brightness level"
+PythonIsNaN = "Ellenörizze hogy x nem NaN"
+PythonKandinskyFunction = "kandinsky modul funkció elötag"
+PythonLdexp = "frexp ellentéte : x*(2**i)"
+PythonLength = "Egy targy hossza"
+PythonLgamma = "Gamma funkció logaritmusa"
+PythonLog = "a alapú logaritmus"
+PythonLog10 = "Decimális logaritmus"
+PythonLog2 = "Bináris logaritmus"
+PythonMathFunction = "math modul funkció elötag"
+PythonMatplotlibPyplotFunction = "matplotlib.pyplot elötag"
+PythonMax = "Maximum"
+PythonMin = "Minimum"
+PythonModf = "x-nek tört és egész részei"
+PythonMonotonic = "Az óra értékét adja vissza"
+PythonNumpyFunction = "numpy elötag"
+PythonNumpyFftFunction = "numpy.fft elötag"
+PythonNumpyLinalgFunction = "numpy.linalg elötag"
+PythonScipyFunction = "scipy elötag"
+PythonScipyLinalgFunction = "scipy.linalg elötag"
+PythonScipyOptimizeFunction = "scipy.optimize elötag"
+PythonScipySignalFunction = "scipy.signal elötag"
+PythonScipySpecialFunction = "scipy.special elötag"
+PythonOct = "Decimális szám konvertálása octális számra"
+PythonPhase = "z fázisa"
+PythonPlot = "y-t jelöli x függvényében"
+PythonPolar = "Verctorizálni"
+PythonPop = "Az utolsó elemet el törölni"
+PythonPower = "x y. kitevö"
+PythonPrint = "Ki irni a elemeket"
+PythonRadians = "Fokról radiánra konvertálni"
+PythonRandint = "Véletlen egész szám [a;b] -ban"
+PythonRandom = "Decimális szám [0;1] -ban"
+PythonRandomFunction = "random modul funkció elötag"
+PythonRandrange = "Véletlen szám range(start,stop)-ban"
+PythonRangeStartStop = "start-tol stop-ig listája"
+PythonRangeStop = "0 tol stop-ig lista"
+PythonRect = "Algebrai számra konvertálni"
+PythonRemove = "Elsö x elöfordulását törolni"
+PythonReverse = "A lista elemeit megfordítani (másik irány)"
+PythonRound = "N számjegyre kerekítni"
+PythonScatter = "(x,y) halmaza"
+PythonSeed = "Inicializálni a véletlenszám-választót"
+PythonSetPixel = "Az (x,y) pixel-t ki szinezni"
+PythonShow = "Mutassa az ábrát"
+PythonSin = "Szinusz"
+PythonSinh = "Hiperbolikus szinusz"
+PythonSleep = "t másodpercre meg állitani a programmot"
+PythonLocalTime = "Idő konvertálása csomóvá"
+PythonMktime = "A tuple konvertálása az időben"
+PythonTime = "Az aktuális időbélyeg letöltése"
+PythonSetLocaltime = "Idő beállítása egy csomóból"
+PythonRTCmode = "Aktuális RTC mód"
+PythonSetRTCmode = "RTC mód beállítása"
+PythonSort = "A listát rendezni"
+PythonSqrt = "Négyzetgyök"
+PythonSum = "Összeadni a lista elemeit"
+PythonTan = "Érintö (tan)"
+PythonTanh = "Hiperbolikus érintö (tan)"
+PythonText = "(x,y) nél egy szöveget irni"
+PythonTimeFunction = "time funkció elötag"
+PythonTrunc = "Egész csonka (?)"
+PythonTurtleBackward = "x pixelt hátra"
+PythonTurtleCircle = "r pixel sugarú kört rajzolni"
+PythonTurtleColor = "Toll szinét beállitani"
+PythonTurtleColorMode = "Szin módot 1.0-ra vagy 255-ra állitani"
+PythonTurtleForward = "x pixelt elölre"
+PythonTurtleFunction = "turtle modul funkció elötag"
+PythonTurtleGoto = "Menjen a (x,y) koordinátákra"
+PythonTurtleHeading = "Visszaadja az aktuális irányt"
+PythonTurtleHideturtle = "A teknös elrejtése"
+PythonTurtleIsdown = "True-t válaszol ha a toll irás pozícióban van"
+PythonTurtleLeft = "a fokkot forduljon balra"
+PythonTurtlePendown = "Húzza le a tollat"
+PythonTurtlePensize = "Állítsa a vonalvastagságot x pixelre"
+PythonTurtlePenup = "Húzza fel a tollat"
+PythonTurtlePosition = "Az aktuális (x,y) pozíciót visszaadása"
+PythonTurtleReset = "Visszaállitani a rajzot (torléssel)"
+PythonTurtleRight = "a fokkot forduljon jobbra"
+PythonTurtleSetheading = "a fokokra állítja be az irányt"
+PythonTurtleShowturtle = "A teknöst meg mutatni"
+PythonTurtleSpeed = "Rajzolási sebesség 0 és 10 között"
+PythonTurtleWrite = "Szöveg irás"
+PythonUniform = "Lebegöpontos szám [a,b] -ban"
+PythonImportTime = "time modul importálása"
+PythonMonotonic = "Meg fordítani a monoton idö"
+PythonFileOpen = "Fájl megnyitása"
+PythonFileSeekable = "Seek-et lehete használni"
+PythonFileSeek = "A kurzort áthelyezni"
+PythonFileTell = "Visszaadja a kurzor helye"
+PythonFileClose = "Bezárni egy fájlt"
+PythonFileClosed = "True ha a fájl bezárva"
+PythonFileRead = "Olvas 16 bájtig"
+PythonFileWrite = "b-t irjon a fájlba"
+PythonFileReadline = "Olvas egy sort vagy 16 bájtig"
+PythonFileReadlines = "Olvas több sort"
+PythonFileTruncate = "A fájl átméretezése"
+PythonFileWritelines = "Irjon több sort"
+PythonFileName = "A fájl neve"
+PythonFileMode = "A fájl nyitott módja"
+PythonFileReadable = "read-et lehete használni"
+PythonFileWritable = "write-ot lehete használni"
+PythonImportOs = "os modul importálása"
+PythonOsUname = "Rendszer informaciók"
+PythonOsGetlogin = "Get username"
+PythonOsRemove = "Fájl törlése"
+PythonOsRename = "Fájl átnevezése"
+PythonOsListdir = "Fájlok listája"
+PythonImportSys = "sys modul importálása"
+PythonSysExit = "Terminate current program"
+PythonSysPrintexception = "Print exception"
+PythonSysByteorder = "The byte order of the system"
+PythonSysImplementation = "Information about Python"
+PythonSysModules = "Dictionary of loaded modules"
+PythonSysVersion = "Python language version (string)"
+PythonSysVersioninfo = "Python language version (tuple)"
+PythonKeyLeft = "BALRA NYÍL billentyű"
+PythonKeyUp = "FEL NYÍL billentyű"
+PythonKeyDown = "LE NYÍL billentyű"
+PythonKeyRight = "JOBBRA NYÍL billentyű"
+PythonKeyOk = "OK gomb"
+PythonKeyBack = "VISSZA gomb"
+PythonKeyHome = "Lakáskulcs"
+PythonKeyOnOff = "BE/KI gomb"
+PythonKeyShift = "SHIFT billentyű"
+PythonKeyAlpha = "ALPHA kulcs"
+PythonKeyXnt = "X,N,T gomb"
+PythonKeyVar = "VAR gomb"
+PythonKeyToolbox = "TOOLBOX gomb"
+PythonKeyBackspace = "BACKSPACE billentyű"
+PythonKeyExp = "EXPONENTIÁLIS kulcs"
+PythonKeyLn = "TERMÉSZETES LOGARITMUS kulcs"
+PythonKeyLog = "DECIMÁLIS LOGARITMUS billentyű"
+PythonKeyImaginary = "KÉPZELETES I kulcs"
+PythonKeyComma = "VESZSŰ gomb"
+PythonKeyPower = "POWER gomb"
+PythonKeySine = "SINE gomb"
+PythonKeyCosine = "KOSINUS kulcs"
+PythonKeyTangent = "ÉRINTŐ gomb"
+PythonKeyPi = "PI kulcs"
+PythonKeySqrt = "NÉGYGYÖK kulcs"
+PythonKeySquare = "SZÖGZET billentyű"
+PythonKeySeven = "7 kulcs"
+PythonKeyEight = "8 kulcs"
+PythonKeyNine = "9 kulcs"
+PythonKeyLeftParenthesis = "BAL ZÁRÓZELŐ gomb"
+PythonKeyRightParenthesis = "JOBB ZÁRÓZELŐ billentyű"
+PythonKeyFour = "4 kulcs"
+PythonKeyFive = "5 kulcs"
+PythonKeySix = "6 kulcs"
+PythonKeyMultiplication = "SZORZAT gomb"
+PythonKeyDivision = "OSZTÁS kulcs"
+PythonKeyOne = "1 kulcs"
+PythonKeyTwo = "2 kulcs"
+PythonKeyThree = "3 kulcs"
+PythonKeyPlus = "PLUSZ kulcs"
+PythonKeyMinus = "MÍNUS gomb"
+PythonKeyZero = "0 kulcs"
+PythonKeyDot = "DOT gomb"
+PythonKeyEe = "10 POWER X gomb"
+PythonKeyAns = "ANS kulcs"
+PythonKeyExe = "EXE kulcs"
+PythonImportUtils = "Az ulab.utils importálása"
+PythonUtilsFunction = "utils modul függvény előtagja"
diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n
index 6c174b53c9e..d839de5418a 100644
--- a/apps/code/catalog.it.i18n
+++ b/apps/code/catalog.it.i18n
@@ -1,5 +1,11 @@
PythonPound = "Commento"
PythonPercent = "Modulo"
+PythonColon = "Due punti"
+PythonSemicon = "Punto e virgola"
+PythonExclamationMark = "Punto esclamativo"
+PythonLessThan = "Minore di"
+PythonGreaterThan = "Maggiore di"
+PythonQuestionMark = "Punto interrogativo"
Python1J = "Unità immaginaria"
PythonLF = "Nuova riga"
PythonTab = "Tabulazione"
@@ -25,7 +31,7 @@ PythonBin = "Converte un intero in binario"
PythonCeil = "Parte intera superiore"
PythonChoice = "Numero aleatorio nella lista"
PythonClear = "Svuota la lista"
-PythonCmathFunction = "Funz. prefissata modulo cmath"
+PythonCmathFunction = "Prefisso funzione del modulo cmath"
PythonColor = "Definisci un colore rvb"
PythonColorBlack = "Colore nero"
PythonColorBlue = "Colore blu"
@@ -45,6 +51,7 @@ PythonCosh = "Coseno iperbolico"
PythonCount = "Conta le ricorrenze di x"
PythonDegrees = "Conversione di radianti in gradi"
PythonDivMod = "Quoziente e resto"
+PythonDrawCircle = "Disegnare un cerchio"
PythonDrawLine = "Disegna una linea"
PythonDrawString = "Visualizza il testo dal pixel x,y"
PythonErf = "Funzione d'errore"
@@ -52,13 +59,18 @@ PythonErfc = "Funzione d'errore complementare"
PythonEval = "Valuta l'espressione nell'argomento "
PythonExp = "Funzione esponenziale"
PythonExpm1 = "Calcola exp(x)-1"
+PythonFactorial = "Fattoriale di x"
PythonFabs = "Valore assoluto"
+PythonFillCircle = "Riempire un cerchio"
+PythonFillPolygon = "Riempire un poligono"
PythonFillRect = "Riempie un rettangolo"
PythonFloat = "Conversione in flottanti"
PythonFloor = "Parte intera"
PythonFmod = "a modulo b"
PythonFrExp = "Mantissa ed esponente di x : (m,e)"
PythonGamma = "Funzione gamma"
+PythonGetKeys = "Ottieni i tasti premuti"
+PythonGetPalette = "Ottieni la tavolozza del tema"
PythonGetPixel = "Restituisce colore del pixel(x,y)"
PythonGetrandbits = "Numero aleatorio con k bit"
PythonGrid = "Attiva la visibilità della griglia"
@@ -70,24 +82,85 @@ PythonImportKandinsky = "Importa modulo kandinsky"
PythonImportRandom = "Importa modulo random"
PythonImportMath = "Importa modulo math"
PythonImportMatplotlibPyplot = "Importa modulo matplotlib.pyplot"
+PythonImportNumpy = "Importa modulo ulab.numpy"
+PythonImportScipy = "Importa modulo ulab.scipy"
PythonImportTurtle = "Importa del modulo turtle"
PythonImportTime = "Importa del modulo time"
PythonImportOs = "Importa modulo os"
PythonOsUname = "Ottieni informazioni sul sistema"
-PythonOsGetlogin = "Get username"
+PythonOsGetlogin = "Ottieni username"
PythonOsRemove = "Rimuovere un file"
PythonOsRename = "Rinomina file"
PythonOsListdir = "Elenca file"
+PythonImportSys = "Importa modulo sys"
+PythonSysExit = "Termina programma corrente"
+PythonSysPrintexception = "Stampa eccezione"
+PythonSysByteorder = "Ordine di byte del sistema"
+PythonSysImplementation = "Informazioni su Python"
+PythonSysModules = "Dizionario dei moduli caricati"
+PythonSysVersion = "Versione linguaggio Python (stringa)"
+PythonSysVersioninfo = "Versione linguaggio Python (tupla)"
PythonIndex = "Indice prima occorrenza di x"
PythonInput = "Inserire un valore"
PythonInsert = "Inserire x in posizione i-esima"
PythonInt = "Conversione in intero"
PythonIonFunction = "Prefisso di funzione modulo ion"
PythonIsFinite = "Testa se x è finito"
-PythonIsInfinite = "Testa se x est infinito"
+PythonIsInfinite = "Testa se x è infinito"
PythonIsKeyDown = "Restituisce True premendo tasto k"
+PythonBattery = "Restituisce la tensione della batteria"
+PythonBatteryLevel = "Restituisce il livello della batteria"
+PythonBatteryIscharging = "Restituisce se la batteria è in carica"
+PythonSetBrightness = "Imposta livello di luminosità"
+PythonGetBrightness = "Ottieni livello di luminosità"
PythonIsNaN = "Testa se x è NaN"
PythonKandinskyFunction = "Prefisso funzione modulo kandinsky"
+PythonKeyLeft = "Tasto FRECCIA SINISTRA"
+PythonKeyUp = "Tasto FRECCIA ALTO"
+PythonKeyDown = "Tasto FRECCIA BASSO"
+PythonKeyRight = "Tasto FRECCIA DESTRA"
+PythonKeyOk = "Tasto OK"
+PythonKeyBack = "Tasto INDIETRO"
+PythonKeyHome = "Tasto CASA"
+PythonKeyOnOff = "Tasto ON/OFF"
+PythonKeyShift = "Tasto SHIFT"
+PythonKeyAlpha = "Tasto ALPHA"
+PythonKeyXnt = "Tasto X,N,T"
+PythonKeyVar = "Tasto VAR"
+PythonKeyToolbox = "Tasto TOOLBOX"
+PythonKeyBackspace = "Tasto CANCELLA"
+PythonKeyExp = "Tasto ESPONENZIALE"
+PythonKeyLn = "Tasto LOGARITMO NEPERIANO"
+PythonKeyLog = "Tasto LOGARITMO DECIMALE"
+PythonKeyImaginary = "Tasto I IMMAGINE"
+PythonKeyComma = "Tasto VIRGOLA"
+PythonKeyPower = "Tasto POTENZA"
+PythonKeySine = "Tasto SENO"
+PythonKeyCosine = "Tasto COSENO"
+PythonKeyTangent = "Tasto TANGENTE"
+PythonKeyPi = "Tasto PI"
+PythonKeySqrt = "Tasto RADICE QUADRATA"
+PythonKeySquare = "Tasto QUADRATO"
+PythonKeySeven = "Tasto 7"
+PythonKeyEight = "Tasto 8"
+PythonKeyNine = "Tasto 9"
+PythonKeyLeftParenthesis = "Tasto PARENTESI SINISTRA"
+PythonKeyRightParenthesis = "Tasto PARENTESI DESTRA"
+PythonKeyFour = "Tasto 4"
+PythonKeyFive = "Tasto 5"
+PythonKeySix = "Tasto 6"
+PythonKeyMultiplication = "Tasto MOLTIPLICAZIONE"
+PythonKeyDivision = "Tasto DIVISIONE"
+PythonKeyOne = "Tasto 1"
+PythonKeyTwo = "Tasto 2"
+PythonKeyThree = "Tasto 3"
+PythonKeyPlus = "Tasto PIÙ"
+PythonKeyMinus = "Tasto MENO"
+PythonKeyZero = "Tasto 0"
+PythonKeyDot = "Tasto PUNTO"
+PythonKeyEe = "Tasto 10 POTENZA X"
+PythonKeyAns = "Tasto ANS"
+PythonKeyExe = "Tasto EXE"
PythonLdexp = "Inversa di frexp : x*(2**i)"
PythonLength = "Longhezza di un oggetto"
PythonLgamma = "Logaritmo della funzione gamma"
@@ -100,6 +173,14 @@ PythonMax = "Massimo"
PythonMin = "Minimo"
PythonModf = "Parti frazionarie e intere"
PythonMonotonic = "Restituisce il valore dell'orologio"
+PythonNumpyFunction = "Prefisso modulo numpy"
+PythonNumpyFftFunction = "Prefisso modulo numpy.fft"
+PythonNumpyLinalgFunction = "Prefisso modulo numpy.linalg"
+PythonScipyFunction = "Prefisso modulo scipy"
+PythonScipyLinalgFunction = "Prefisso modulo scipy.linalg"
+PythonScipyOptimizeFunction = "Prefisso modulo scipy.optimize"
+PythonScipySignalFunction = "Prefisso modulo scipy.signal"
+PythonScipySpecialFunction = "Prefisso modulo scipy.special"
PythonOct = "Conversione in ottale"
PythonPhase = "Argomento di z"
PythonPlot = "Disegna y in f. di x come linee"
@@ -115,7 +196,7 @@ PythonRandrange = "Numero dentro il range(start, stop)"
PythonRangeStartStop = "Lista da start a stop-1"
PythonRangeStop = "Lista da 0 a stop-1"
PythonRect = "Converte in coordinate algebriche"
-PythonRemove = "Cancella la prima x dalla lista"
+PythonRemove = "Cancella la prima x dalla lista"
PythonReverse = "Inverte gli elementi della lista"
PythonRound = "Arrotondato a n cifre decimali"
PythonScatter = "Diagramma dispersione y in f. di x"
@@ -125,6 +206,12 @@ PythonShow = "Mostra la figura"
PythonSin = "Seno"
PythonSinh = "Seno iperbolico"
PythonSleep = "Sospende l'esecuzione t secondi"
+PythonLocalTime = "Converti il tempo in tuple"
+PythonMktime = "Converti tuple in tempo"
+PythonTime = "Ottieni il timestamp corrente"
+PythonSetLocaltime = "Imposta il tempo da una tupla"
+PythonRTCmode = "Ottieni la modalità RTC corrente"
+PythonSetRTCmode = "Imposta modalità RTC"
PythonSort = "Ordina l'elenco"
PythonSqrt = "Radice quadrata"
PythonSum = "Somma degli elementi della lista"
@@ -151,28 +238,27 @@ PythonTurtlePosition = "Fornisce posizione corrente (x,y)"
PythonTurtleReset = "Azzera il disegno"
PythonTurtleRight = "Ruota di a gradi a destra"
PythonTurtleSetheading = "Imposta l'orientamento per a gradi"
-PythonTurtleSetposition = "Posiziona la tartaruga"
PythonTurtleShowturtle = "Mostra la tartaruga"
PythonTurtleSpeed = "Velocità di disegno (x tra 0 e 10)"
PythonTurtleWrite = "Mostra un testo"
PythonUniform = "Numero decimale tra [a,b]"
-PythonImportTime = "Import time module"
-PythonTimePrefix = "time module function prefix"
-PythonTimeSleep = "Wait for n second"
-PythonMonotonic = "Return monotonic time"
-PythonFileOpen = "Opens a file"
-PythonFileSeekable = "Tells if seek can be used on a file"
-PythonFileSeek = "Move file's cursor"
-PythonFileTell = "Get file's cursor location"
-PythonFileClose = "Closes a file"
-PythonFileClosed = "True if file was closed"
-PythonFileRead = "Read up to size bytes"
-PythonFileWrite = "Write b into file"
-PythonFileReadline = "Reads a line or up to size bytes"
-PythonFileReadlines = "Reads a list of lines"
-PythonFileTruncate = "Resize the file to size"
-PythonFileWritelines = "Writes a list of lines"
-PythonFileName = "Contains file's name"
-PythonFileMode = "Contains file's open mode"
-PythonFileReadable = "Tells if read can be used on a file"
-PythonFileWritable = "Tells if write can be used on a file"
+PythonImportTime = "Importa modulo time"
+PythonMonotonic = "Restituisce tempo monotonico"
+PythonFileOpen = "Apre un file"
+PythonFileSeekable = "Dice se si può usare il cursore su un file"
+PythonFileSeek = "Sposta cursore di un file"
+PythonFileTell = "Ottieni posizione del cursore del file"
+PythonFileClose = "Chiude un file"
+PythonFileClosed = "True se un file è stato chiuso"
+PythonFileRead = "Legge fino ai byte di un file"
+PythonFileWrite = "Scrive b in un file"
+PythonFileReadline = "Legge una riga o fino ai byte di un file"
+PythonFileReadlines = "Legge una lista di linee di un file"
+PythonFileTruncate = "Ridimensiona il file"
+PythonFileWritelines = "Scrive una lista di linee su file"
+PythonFileName = "Contiene il nome del file"
+PythonFileMode = "Contiene la modalità di apertura del file"
+PythonFileReadable = "Dice se si può leggere sul file"
+PythonFileWritable = "Dice se si può scrivere sul file"
+PythonImportUtils = "Importazione di ulab.utils"
+PythonUtilsFunction = "Prefisso funzione del modulo utils"
diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n
index cc788ee135e..4ba8d9906c5 100644
--- a/apps/code/catalog.nl.i18n
+++ b/apps/code/catalog.nl.i18n
@@ -1,5 +1,11 @@
PythonPound = "Opmerkingen"
PythonPercent = "Modulo"
+PythonColon = "Dubbele punt"
+PythonSemicon = "Puntkomma"
+PythonExclamationMark = "Uitroepteken"
+PythonLessThan = "Kleiner dan"
+PythonGreaterThan = "Groter dan"
+PythonQuestionMark = "Vraagteken"
Python1J = "Imaginaire i"
PythonLF = "Nieuwe regel"
PythonTab = "Tabulatie"
@@ -45,6 +51,7 @@ PythonCosh = "Cosinus hyperbolicus"
PythonCount = "Tel voorkomen van x"
PythonDegrees = "Zet x om van radialen naar graden"
PythonDivMod = "Quotiënt en rest"
+PythonDrawCircle = "Teken een cirkel"
PythonDrawLine = "Teken een lijn"
PythonDrawString = "Geef een tekst weer van pixel (x,y)"
PythonErf = "Error functie"
@@ -52,13 +59,18 @@ PythonErfc = "Complementaire error functie"
PythonEval = "Geef de geëvalueerde uitdrukking"
PythonExp = "Exponentiële functie"
PythonExpm1 = "Bereken exp(x)-1"
+PythonFactorial = "faculteit van x"
PythonFabs = "Absolute waarde"
+PythonFillCircle = "Vul een cirkel"
+PythonFillPolygon = "Vul een veelhoek"
PythonFillRect = "Vul een rechthoek bij pixel (x,y)"
PythonFloat = "Zet x om in een float"
PythonFloor = "Vloer"
PythonFmod = "a modulo b"
PythonFrExp = "Mantisse en exponent van x: (m,e)"
PythonGamma = "Gammafunctie"
+PythonGetKeys = "Get toetsen ingedrukt"
+PythonGetPalette = "Thema palet krijgen"
PythonGetPixel = "Geef pixel (x,y) kleur (rgb)"
PythonGetrandbits = "Integer met k willekeurige bits"
PythonGrid = "Verander zichtbaarheid raster"
@@ -70,6 +82,8 @@ PythonImportKandinsky = "Importeer kandinsky module"
PythonImportRandom = "Importeer random module"
PythonImportMath = "Importeer math module"
PythonImportMatplotlibPyplot = "Importeer matplotlib.pyplot module"
+PythonImportNumpy = "Importeer ulab.numpy module"
+PythonImportScipy = "Importeer ulab.scipy module"
PythonImportTime = "Importeer time module"
PythonImportOs = "Importeer os module"
PythonOsUname = " Krijg systeeminfo"
@@ -77,6 +91,15 @@ PythonOsGetlogin = "Get username"
PythonOsRemove = "Een bestand verwijderen"
PythonOsRename = "Hernoem bestand"
PythonOsListdir = "Lijstbestanden"
+PythonImportSys = "Importeer sys module"
+PythonImportSys = "Importeer sys module"
+PythonSysExit = "Terminate current program"
+PythonSysPrintexception = "Print exception"
+PythonSysByteorder = "The byte order of the system"
+PythonSysImplementation = "Information about Python"
+PythonSysModules = "Dictionary of loaded modules"
+PythonSysVersion = "Python language version (string)"
+PythonSysVersioninfo = "Python language version (tuple)"
PythonImportTurtle = "Importeer turtle module"
PythonIndex = "Index van de eerste x aanwezigheden"
PythonInput = "Wijs een waarde toe"
@@ -86,8 +109,59 @@ PythonIonFunction = "ion module voorvoegsel"
PythonIsFinite = "Controleer of x eindig is"
PythonIsInfinite = "Controleer of x oneindig is"
PythonIsKeyDown = "Geef True als k toets omlaag is"
+PythonBattery = "Return batterijspanning"
+PythonBatteryLevel = "Batterijniveau teruggeven"
+PythonBatteryIscharging = "Keer terug als de batterij wordt opgeladen"
+PythonSetBrightness = "Set brightness level"
+PythonGetBrightness = "Get brightness level"
PythonIsNaN = "Controleer of x geen getal is"
PythonKandinskyFunction = "kandinsky module voorvoegsel"
+PythonKeyLeft = "PIJL NAAR LINKS toets"
+PythonKeyUp = "PIJL OMHOOG toets"
+PythonKeyDown = "PIJL OMLAAG toets"
+PythonKeyRight = "PIJL NAAR RECHTS toets"
+PythonKeyOk = "OK toets"
+PythonKeyBack = "TERUG toets"
+PythonKeyHome = "HOME toets"
+PythonKeyOnOff = "AAN/UIT toets"
+PythonKeyShift = "SHIFT toets"
+PythonKeyAlpha = "ALPHA toets"
+PythonKeyXnt = "X,N,T toets"
+PythonKeyVar = "VAR toets"
+PythonKeyToolbox = "TOOLBOX toets"
+PythonKeyBackspace = "BACKSPACE toets"
+PythonKeyExp = "EXPONENTIEEL toets"
+PythonKeyLn = "NATUURLIJKE LOGARITME toets"
+PythonKeyLog = "BRIGGSE LOGARITME toets"
+PythonKeyImaginary = "IMAGINAIRE I toets"
+PythonKeyComma = "KOMMA toets"
+PythonKeyPower = "MACHT toets"
+PythonKeySine = "SINUS toets"
+PythonKeyCosine = "COSINUS toets"
+PythonKeyTangent = "TANGENS toets"
+PythonKeyPi = "PI toets"
+PythonKeySqrt = "VIERKANTSWORTEL toets"
+PythonKeySquare = "KWADRAAT toets"
+PythonKeySeven = "7 toets"
+PythonKeyEight = "8 toets"
+PythonKeyNine = "9 toets"
+PythonKeyLeftParenthesis = "HAAKJE OPENEN toets"
+PythonKeyRightParenthesis = "HAAKJE SLUITEN toets"
+PythonKeyFour = "4 toets"
+PythonKeyFive = "5 toets"
+PythonKeySix = "6 toets"
+PythonKeyMultiplication = "VERMENIGVULDIGEN toets"
+PythonKeyDivision = "DELEN toets"
+PythonKeyOne = "1 toets"
+PythonKeyTwo = "2 toets"
+PythonKeyThree = "3 toets"
+PythonKeyPlus = "PLUS toets"
+PythonKeyMinus = "MIN toets"
+PythonKeyZero = "0 toets"
+PythonKeyDot = "PUNT toets"
+PythonKeyEe = "10 TOT DE MACHT X toets"
+PythonKeyAns = "ANS toets"
+PythonKeyExe = "EXE toets"
PythonLdexp = "Geeft x*(2**i), inversie van frexp"
PythonLength = "Lengte van een object"
PythonLgamma = "Log-gammafunctie"
@@ -100,6 +174,14 @@ PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractionele en gehele delen van x"
PythonMonotonic = "Waarde van een monotone klok"
+PythonNumpyFunction = "numpy module prefix"
+PythonNumpyFftFunction = "numpy.fft module prefix"
+PythonNumpyLinalgFunction = "numpy.linalg module prefix"
+PythonScipyFunction = "scipy module prefix"
+PythonScipyLinalgFunction = "scipy.linalg module prefix"
+PythonScipyOptimizeFunction = "scipy.optimize module prefix"
+PythonScipySignalFunction = "scipy.signal module prefix"
+PythonScipySpecialFunction = "scipy.special module prefix"
PythonOct = "Integer omzetten naar octaal"
PythonPhase = "Fase van z in radialen"
PythonPlot = "Plot y versus x als lijnen"
@@ -122,9 +204,15 @@ PythonScatter = "Teken scatterplot van y versus x"
PythonSeed = "Start willek. getallengenerator"
PythonSetPixel = "Kleur pixel (x,y)"
PythonShow = "Figuur weergeven"
-PythonSin= "Sinus"
+PythonSin = "Sinus"
PythonSinh = "Sinus hyperbolicus"
PythonSleep = "Stel executie voor t seconden uit"
+PythonLocalTime = "Zet tijd om in tuple"
+PythonMktime = "Tuple omzetten in tijd"
+PythonTime = "Haal de huidige tijdstempel"
+PythonSetLocaltime = "Stel de tijd in vanaf een tuple"
+PythonRTCmode = "Huidige RTC-modus kregen"
+PythonSetRTCmode = "RTC-modus instellen"
PythonSort = "Sorteer de lijst"
PythonSqrt = "Vierkantswortel"
PythonSum = "Sommeer de items van een lijst"
@@ -151,14 +239,11 @@ PythonTurtlePosition = "Zet huidige (x,y) locatie terug"
PythonTurtleReset = "Reset de tekening"
PythonTurtleRight = "Ga rechtsaf met a graden"
PythonTurtleSetheading = "Zet de oriëntatie op a graden"
-PythonTurtleSetposition = "Plaats de schildpad"
PythonTurtleShowturtle = "Laat de schildpad zien"
PythonTurtleSpeed = "Tekensnelheid tussen 0 and 10"
PythonTurtleWrite = "Display a text"
PythonUniform = "Decimaal getal in [a,b]"
PythonImportTime = "Import time module"
-PythonTimePrefix = "time module function prefix"
-PythonTimeSleep = "Wait for n second"
PythonMonotonic = "Return monotonic time"
PythonFileOpen = "Opens a file"
PythonFileSeekable = "Tells if seek can be used on a file"
@@ -176,3 +261,5 @@ PythonFileName = "Contains file's name"
PythonFileMode = "Contains file's open mode"
PythonFileReadable = "Tells if read can be used on a file"
PythonFileWritable = "Tells if write can be used on a file"
+PythonImportUtils = "Ulab.utils importeren"
+PythonUtilsFunction = "utils module functie prefix"
diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n
index d50630dda74..bc740acdf7f 100644
--- a/apps/code/catalog.pt.i18n
+++ b/apps/code/catalog.pt.i18n
@@ -1,5 +1,11 @@
PythonPound = "Comentário"
PythonPercent = "Módulo"
+PythonColon = "Dois pontos"
+PythonSemicon = "Ponto e vírgula"
+PythonExclamationMark = "Ponto de exclamação"
+PythonLessThan = "Menor que"
+PythonGreaterThan = "Maior que"
+PythonQuestionMark = "Ponto de interrogação"
Python1J = "i Complexo"
PythonLF = "Nova linha"
PythonTab = "Tabulação"
@@ -45,6 +51,7 @@ PythonCosh = "Cosseno hiperbólico"
PythonCount = "Contar as ocorrências de x"
PythonDegrees = "Converter x de radianos para graus"
PythonDivMod = "Quociente e resto"
+PythonDrawCircle = "Desenha um círculo"
PythonDrawLine = "Desenhe uma linha"
PythonDrawString = "Mostrar o texto do pixel (x,y)"
PythonErf = "Função erro"
@@ -52,13 +59,18 @@ PythonErfc = "Função erro complementar"
PythonEval = "Devolve a expressão avaliada"
PythonExp = "Função exponencial"
PythonExpm1 = "Calcular exp(x)-1"
+PythonFactorial = "Fatorial de x"
PythonFabs = "Valor absoluto"
+PythonFillCircle = "Preencher um círculo"
+PythonFillPolygon = "Preencher um polígono"
PythonFillRect = "Preencher um retângulo em (x,y)"
PythonFloat = "Converter x num flutuante"
PythonFloor = "Parte inteira"
PythonFmod = "a módulo b"
PythonFrExp = "Coeficiente e expoente de x: (m, e)"
PythonGamma = "Função gama"
+PythonGetKeys = "Obter teclas pressionadas"
+PythonGetPalette = "Obter paleta temática"
PythonGetPixel = "Devolve a cor do pixel (x,y)"
PythonGetrandbits = "Número inteiro aleatório com k bits"
PythonGrid = "Alterar visibilidade da grelha"
@@ -70,6 +82,8 @@ PythonImportKandinsky = "Importar módulo kandinsky"
PythonImportRandom = "Importar módulo random"
PythonImportMath = "Importar módulo math"
PythonImportMatplotlibPyplot = "Importar módulo matplotlib.pyplot"
+PythonImportNumpy = "Importar módulo ulab.numpy"
+PythonImportScipy = "Importar módulo ulab.scipy"
PythonImportTime = "Importar módulo time"
PythonImportTurtle = "Importar módulo turtle"
PythonIndex = "Índice da primeira ocorrência de x"
@@ -80,8 +94,59 @@ PythonIonFunction = "Prefixo da função do módulo ion"
PythonIsFinite = "Verificar se x é finito"
PythonIsInfinite = "Verificar se x é infinito"
PythonIsKeyDown = "Devolve True se tecla k pressionada"
+PythonBattery = "Retornar a voltagem da bateria"
+PythonBatteryLevel = "Retornar nível de bateria"
+PythonBatteryIscharging = "Retorne se a bateria estiver carregando"
+PythonSetBrightness = "Definir nível de brilho"
+PythonGetBrightness = "Obter nível de brilho"
PythonIsNaN = "Verificar se x é um NaN"
PythonKandinskyFunction = "Prefixo da função do módulo kandinsky"
+PythonKeyLeft = "tecla SETA ESQUERDA"
+PythonKeyUp = "tecla SETA CIMA "
+PythonKeyDown = "tecla SETA BAIXO"
+PythonKeyRight = "tecla SETA DIREITA"
+PythonKeyOk = "tecla OK"
+PythonKeyBack = "tecla VOLTAR"
+PythonKeyHome = "tecla HOME"
+PythonKeyOnOff = "tecla ON/OFF"
+PythonKeyShift = "tecla SHIFT"
+PythonKeyAlpha = "tecla ALPHA"
+PythonKeyXnt = "tecla X,N,T"
+PythonKeyVar = "tecla VAR"
+PythonKeyToolbox = "tecla CAIXA DE FERRAMENTAS"
+PythonKeyBackspace = "tecla APAGAR"
+PythonKeyExp = "tecla EXPONENCIAL"
+PythonKeyLn = "tecla LOGARITMO NATURAL"
+PythonKeyLog = "tecla LOGARITMO DECIMAL"
+PythonKeyImaginary = "tecla I IMAGINÁRIO"
+PythonKeyComma = "tecla VÍRGULA"
+PythonKeyPower = "tecla EXPOENTE"
+PythonKeySine = "tecla SENO"
+PythonKeyCosine = "tecla COSSENO"
+PythonKeyTangent = "tecla TANGENTE"
+PythonKeyPi = "tecla PI"
+PythonKeySqrt = "tecla RAIZ QUADRADA"
+PythonKeySquare = "tecla AO QUADRADO"
+PythonKeySeven = "tecla 7"
+PythonKeyEight = "tecla 8"
+PythonKeyNine = "tecla 9"
+PythonKeyLeftParenthesis = "tecla PARÊNTESE ESQUERDO"
+PythonKeyRightParenthesis = "tecla PARÊNTESE DIREITO"
+PythonKeyFour = "tecla 4"
+PythonKeyFive = "tecla 5"
+PythonKeySix = "tecla 6"
+PythonKeyMultiplication = "tecla MULTIPLICAÇÃO"
+PythonKeyDivision = "tecla DIVISÃO"
+PythonKeyOne = "tecla 1"
+PythonKeyTwo = "tecla 2"
+PythonKeyThree = "tecla 3"
+PythonKeyPlus = "tecla MAIS"
+PythonKeyMinus = "tecla MENOS"
+PythonKeyZero = "tecla 0"
+PythonKeyDot = "tecla PONTO"
+PythonKeyEe = "tecla 10 expoente X"
+PythonKeyAns = "tecla ANS"
+PythonKeyExe = "tecla EXE"
PythonLdexp = "Devolve x*(2**i), inverso de frexp"
PythonLength = "Comprimento de um objeto"
PythonLgamma = "Logaritmo da função gama"
@@ -94,6 +159,14 @@ PythonMax = "Máximo"
PythonMin = "Mínimo"
PythonModf = "Partes inteira e frácionária de x"
PythonMonotonic = "Devolve o valor do relógio"
+PythonNumpyFunction = "Prefixo do módulo numpy"
+PythonNumpyFftFunction = "Prefixo do módulo numpy.fft"
+PythonNumpyLinalgFunction = "Prefixo do módulo numpy.linalg"
+PythonScipyFunction = "Prefixo do módulo scipy"
+PythonScipyLinalgFunction = "Prefixo do módulo scipy.linalg"
+PythonScipyOptimizeFunction = "Prefixo do módulo scipy.optimize"
+PythonScipySignalFunction = "Prefixo do módulo scipy.signal"
+PythonScipySpecialFunction = "Prefixo do módulo scipy.special"
PythonOct = "Converter número inteiro em octal"
PythonPhase = "Argumento de z"
PythonPlot = "Desenhar y em função de x"
@@ -119,6 +192,12 @@ PythonShow = "Mostrar a figura"
PythonSin = "Seno"
PythonSinh = "Seno hiperbólico"
PythonSleep = "Suspender a execução por t segundos"
+PythonLocalTime = "Convert o tempo em tupla"
+PythonMktime = "Convert tuple em tempo"
+PythonTime = "Obter o estamp de tempo atual"
+PythonSetLocaltime = "Definir tempo a partir de uma tupla"
+PythonRTCmode = "Obter o modo RTC atual"
+PythonSetRTCmode = "Definir o modo RTC"
PythonSort = "Ordenar a lista"
PythonSqrt = "Raiz quadrada"
PythonSum = "Soma dos itens da lista"
@@ -145,7 +224,6 @@ PythonTurtlePosition = "Devolve a posição atual (x,y)"
PythonTurtleReset = "Reiniciar o desenho"
PythonTurtleRight = "Virar à esquerda por a graus"
PythonTurtleSetheading = "Definir a orientação por a graus"
-PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Mostrar o turtle"
PythonTurtleSpeed = "Velocidade do desenho entre 0 e 10"
PythonTurtleWrite = "Mostrar um texto"
@@ -157,8 +235,14 @@ PythonOsGetlogin = "Get username"
PythonOsRemove = "Remover um ficheiro"
PythonOsRename = "Renomear ficheiro"
PythonOsListdir = "Listar ficheiros"
-PythonTimePrefix = "time module function prefix"
-PythonTimeSleep = "Wait for n second"
+PythonImportSys = "Import sys module"
+PythonSysExit = "Terminate current program"
+PythonSysPrintexception = "Print exception"
+PythonSysByteorder = "The byte order of the system"
+PythonSysImplementation = "Information about Python"
+PythonSysModules = "Dictionary of loaded modules"
+PythonSysVersion = "Python language version (string)"
+PythonSysVersioninfo = "Python language version (tuple)"
PythonMonotonic = "Return monotonic time"
PythonFileOpen = "Opens a file"
PythonFileSeekable = "Tells if seek can be used on a file"
@@ -176,3 +260,5 @@ PythonFileName = "Contains file's name"
PythonFileMode = "Contains file's open mode"
PythonFileReadable = "Tells if read can be used on a file"
PythonFileWritable = "Tells if write can be used on a file"
+PythonImportUtils = "Importando ulab.utils"
+PythonUtilsFunction = "prefixo de função do módulo utils"
diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n
index 0c05ad6f460..09d292f7c25 100644
--- a/apps/code/catalog.universal.i18n
+++ b/apps/code/catalog.universal.i18n
@@ -1,6 +1,12 @@
PythonCommandAmpersand = "&"
PythonCommandLF = "\\n"
PythonCommandPercent = "%"
+PythonCommandColon = ":"
+PythonCommandSemicon = ";"
+PythonCommandExclamationMark = "!"
+PythonCommandLessThan = "<"
+PythonCommandGreaterThan = ">"
+PythonCommandQuestionMark = "?"
PythonCommandPound = "#"
PythonCommandSingleQuote = "'x'"
PythonCommandSymbolExp = "^"
@@ -50,6 +56,7 @@ PythonCommandCount = "list.count(x)"
PythonCommandCountWithoutArg = ".count(\x11)"
PythonCommandDegrees = "degrees(x)"
PythonCommandDivMod = "divmod(a,b)"
+PythonCommandDrawCircle = "draw_circle(x,y,r,color)"
PythonCommandDrawLine = "draw_line(x1,y1,x2,y2,color)"
PythonCommandDrawString = "draw_string(\"text\",x,y)"
PythonCommandConstantE = "e"
@@ -59,13 +66,18 @@ PythonCommandEval = "eval(\"expression\")"
PythonCommandExp = "exp(x)"
PythonCommandExpComplex = "exp(z)"
PythonCommandExpm1 = "expm1(x)"
+PythonCommandFactorial = "factorial(x)"
PythonCommandFabs = "fabs(x)"
+PythonCommandFillCircle = "fill_circle(x,y,r,color)"
+PythonCommandFillPolygon = "fill_polygon([(x1,y1),...],color)"
PythonCommandFillRect = "fill_rect(x,y,width,height,color)"
PythonCommandFloat = "float(x)"
PythonCommandFloor = "floor(x)"
PythonCommandFmod = "fmod(a,b)"
PythonCommandFrExp = "frexp(x)"
PythonCommandGamma = "gamma(x)"
+PythonCommandGetKeys = "get_keys()"
+PythonCommandGetPalette = "get_palette()"
PythonCommandGetPixel = "get_pixel(x,y)"
PythonCommandGetrandbits = "getrandbits(k)"
PythonCommandGrid = "grid()"
@@ -86,9 +98,13 @@ PythonCommandImportIon = "import ion"
PythonCommandImportKandinsky = "import kandinsky"
PythonCommandImportMath = "import math"
PythonCommandImportMatplotlibPyplot = "import matplotlib.pyplot"
+PythonCommandImportFromNumpy = "from ulab import numpy as np"
+PythonCommandImportFromScipy = "from ulab import scipy as spy"
PythonCommandImportRandom = "import random"
PythonCommandImportOs = "import os"
PythonCommandImportFromOs = "from os import *"
+PythonCommandImportSys = "import sys"
+PythonCommandImportFromSys = "from sys import *"
PythonCommandImportTime = "import time"
PythonCommandImportTurtle = "import turtle"
PythonCommandIndex = "list.index(x)"
@@ -151,6 +167,11 @@ PythonCommandKeyEe = "KEY_EE"
PythonCommandKeyAns = "KEY_ANS"
PythonCommandKeyExe = "KEY_EXE"
PythonCommandIsKeyDown = "keydown(k)"
+PythonCommandBattery = "battery()"
+PythonCommandBatteryLevel = "battery_level()"
+PythonCommandBatteryIscharging = "battery_ischarging()"
+PythonCommandSetBrightness = "set_brightness()"
+PythonCommandGetBrightness = "get_brightness()"
PythonCommandLdexp = "ldexp(x,i)"
PythonCommandLength = "len(object)"
PythonCommandLgamma = "lgamma(x)"
@@ -166,6 +187,128 @@ PythonCommandMax = "max(list)"
PythonCommandMin = "min(list)"
PythonCommandModf = "modf(x)"
PythonCommandMonotonic = "monotonic()"
+PythonCommandNumpyArray = "np.array(a)"
+PythonCommandNumpyArange = "np.arange(i)"
+PythonCommandNumpyConcatenate = "np.concatenate(a,b)"
+PythonCommandNumpyDiag = "np.diag(a)"
+PythonCommandNumpyZeros = "np.zeros(s)"
+PythonCommandNumpyOnes = "np.ones(s)"
+PythonCommandNumpyEmpty = "np.empty(s)"
+PythonCommandNumpyEye = "np.eye(n, m)"
+PythonCommandNumpyFull = "np.full(s, v)"
+PythonCommandNumpyLinspace = "np.linspace(s, e)"
+PythonCommandNumpyLogspace = "np.logspace(s, e)"
+PythonCommandNumpyCopy = "ndarray.copy()"
+PythonCommandNumpyCopyWithoutArg = ".copy()"
+PythonCommandNumpyDtype = "ndarray.dtype"
+PythonCommandNumpyDtypeWithoutArg = ".dtype"
+PythonCommandNumpyFlat = "ndarray.flat"
+PythonCommandNumpyFlatWithoutArg = ".flat"
+PythonCommandNumpyFlatten = "ndarray.flatten()"
+PythonCommandNumpyFlattenWithoutArg = ".flatten()"
+PythonCommandNumpyShape = "ndarray.shape"
+PythonCommandNumpyShapeWithoutArg = ".shape"
+PythonCommandNumpyReshape = "ndarray.reshape(s)"
+PythonCommandNumpyReshapeWithoutArg = ".reshape(\x11)"
+PythonCommandNumpySize = "ndarray.size"
+PythonCommandNumpySizeWithoutArg = ".size"
+PythonCommandNumpyTranspose = "ndarray.transpose()"
+PythonCommandNumpyTransposeWithoutArg = ".transpose()"
+PythonCommandNumpySort = "ndarray.sort()"
+PythonCommandNumpySortWithoutArg = ".sort()"
+PythonCommandNumpyFromBuffer = "ndarray.frombuffer(b)"
+PythonCommandNumpyToBytes = "ndarray.tobytes()"
+PythonCommandNumpyToBytesWithoutArg = ".tobytes()"
+PythonCommandNumpySetPrintOptions = "np.set_printoptions()"
+PythonCommandNumpyGetPrintOptions = "np.get_printoptions()"
+PythonCommandNumpyNdinfo = "np.ndinfo(a)"
+PythonCommandNumpyAll = "np.all(a)"
+PythonCommandNumpyAny = "np.any(a)"
+PythonCommandNumpyArgmax = "np.argmax(a)"
+PythonCommandNumpyArgmin = "np.argmin(a)"
+PythonCommandNumpyArgsort = "np.argsort(a)"
+PythonCommandNumpyClip = "np.clip(a, min, max)"
+PythonCommandNumpyConvolve = "np.convolve(a, b)"
+PythonCommandNumpyDiff = "np.diff(a)"
+PythonCommandNumpyInterp = "np.interp(a)"
+PythonCommandNumpyDot = "np.dot(a, b)"
+PythonCommandNumpyCross = "np.cross(a, b)"
+PythonCommandNumpyEqual = "np.equal(a, b)"
+PythonCommandNumpyNot_equal = "np.not_equal(a, b)"
+PythonCommandNumpyFlip = "np.flip(a)"
+PythonCommandNumpyIsfinite = "np.isfinite(a)"
+PythonCommandNumpyIsinf = "np.isinf(a)"
+PythonCommandNumpyMean = "np.mean(a)"
+PythonCommandNumpyMin = "np.min(a)"
+PythonCommandNumpyMax = "np.max(a)"
+PythonCommandNumpyMedian = "np.median(a)"
+PythonCommandNumpyMinimum = "np.minimum(a, b)"
+PythonCommandNumpyMaximum = "np.maximum(a, b)"
+PythonCommandNumpyPolyfit = "np.polyfit(a, b, y)"
+PythonCommandNumpyPolyval = "np.polyval(p, x)"
+PythonCommandNumpyRoll = "np.roll(a, n)"
+PythonCommandNumpySortWithArguments = "np.sort(a)"
+PythonCommandNumpyStd = "np.std(a)"
+PythonCommandNumpySum = "np.sum(a)"
+PythonCommandNumpyTrace = "np.trace(a)"
+PythonCommandNumpyTrapz = "np.trapz(y)"
+PythonCommandNumpyWhere = "np.where(c, x, y)"
+PythonCommandNumpyVectorize = "np.vectorize(f)"
+PythonCommandNumpyAcos = "np.acos(a)"
+PythonCommandNumpyAcosh = "np.acosh(a)"
+PythonCommandNumpyArctan2 = "np.arctan2(a)"
+PythonCommandNumpyAround = "np.around(a)"
+PythonCommandNumpyAsin = "np.asin(a)"
+PythonCommandNumpyAsinh = "np.asinh(a)"
+PythonCommandNumpyAtan = "np.atan(a)"
+PythonCommandNumpyAtanh = "np.atanh(a)"
+PythonCommandNumpyCeil = "np.ceil(a)"
+PythonCommandNumpyCos = "np.cos(a)"
+PythonCommandNumpyCosh = "np.cosh(a)"
+PythonCommandNumpyDegrees = "np.degrees(a)"
+PythonCommandNumpyExp = "np.exp(a)"
+PythonCommandNumpyExpm1 = "np.expm1(a)"
+PythonCommandNumpyFloor = "np.floor(a)"
+PythonCommandNumpyLog = "np.log(a)"
+PythonCommandNumpyLog10 = "np.log10(a)"
+PythonCommandNumpyLog2 = "np.log2(a)"
+PythonCommandNumpyRadians = "np.radians(a)"
+PythonCommandNumpySin = "np.sin(a)"
+PythonCommandNumpySinh = "np.sinh(a)"
+PythonCommandNumpySqrt = "np.sqrt(a)"
+PythonCommandNumpyTan = "np.tan(a)"
+PythonCommandNumpyTanh = "np.tanh(a)"
+PythonCommandNumpyBool = "np.bool"
+PythonCommandNumpyFloat = "np.float"
+PythonCommandNumpyUint8 = "np.uint8"
+PythonCommandNumpyInt8 = "np.int8"
+PythonCommandNumpyUint16 = "np.uint16"
+PythonCommandNumpyInt16 = "np.int16"
+PythonCommandNumpyNan = "np.nan"
+PythonCommandNumpyInf = "np.inf"
+PythonCommandNumpyE = "np.e"
+PythonCommandNumpyPi = "np.pi"
+PythonCommandNumpyFft = "np.fft.fft(a)"
+PythonCommandNumpyIfft = "np.fft.ifft(a)"
+PythonCommandNumpyDet = "np.linalg.det(a)"
+PythonCommandNumpyEig = "np.linalg.eig(a)"
+PythonCommandNumpyCholesky = "np.linalg.cholesky(a)"
+PythonCommandNumpyInv = "np.linalg.inv(a)"
+PythonCommandNumpyNorm = "np.linalg.norm(a)"
+PythonCommandNumpyFunction = "np.function"
+PythonCommandNumpyFunctionWithoutArg = "np.\x11"
+PythonCommandNumpyFftFunction = "np.fft.function"
+PythonCommandNumpyFftFunctionWithoutArg = "np.fft.\x11"
+PythonCommandNumpyLinalgFunction = "np.linalg.function"
+PythonCommandNumpyLinalgFunctionWithoutArg = "np.linalg.\x11"
+PythonCommandImportFromUtils = "from ulab import utils"
+PythonCommandUtilsFunction = "utils.function"
+PythonCommandUtilsFunctionWithoutArg = "utils.\x11"
+PythonCommandUtilsSpectrogram = "spectrogram(a)"
+PythonCommandUtilsFromInt16Buffer = "from_int16_buffer(b)"
+PythonCommandUtilsFromUint16Buffer = "from_uint16_buffer(b)"
+PythonCommandUtilsFromInt32Buffer = "from_int32_buffer(b)"
+PythonCommandUtilsFromUint32Buffer = "from_uint32_buffer(b)"
PythonCommandOct = "oct(x)"
PythonCommandPhase = "phase(z)"
PythonCommandPlot = "plot(x,y,color)"
@@ -192,12 +335,39 @@ PythonCommandReverseWithoutArg = ".reverse()"
PythonCommandRound = "round(x,n)"
PythonCommandScatter = "scatter(x,y)"
PythonCommandSeed = "seed(x)"
+PythonCommandScipyFunction = "spy.function"
+PythonCommandScipyFunctionWithoutArg = "spy.\x11"
+PythonCommandScipyLinalgFunction = "spy.linalg.function"
+PythonCommandScipyLinalgFunctionWithoutArg = "spy.linalg.\x11"
+PythonCommandScipyOptimizeFunction = "spy.optimize.function"
+PythonCommandScipyOptimizeFunctionWithoutArg = "spy.optimize.\x11"
+PythonCommandScipySignalFunction = "spy.signal.function"
+PythonCommandScipySignalFunctionWithoutArg = "spy.signal.\x11"
+PythonCommandScipySpecialFunction = "spy.special.function"
+PythonCommandScipySpecialFunctionWithoutArg = "spy.special.\x11"
+PythonCommandScipyLinalgChoSolve = "spy.linalg.cho_solve(a, b)"
+PythonCommandScipyLinalgSolveTriangular = "spy.linalg.solve_triangular(a, b)"
+PythonCommandScipyOptimizeBisect = "spy.optimize.bisect(f, a, b)"
+PythonCommandScipyOptimizeFmin = "spy.optimize.fmin(f, x0)"
+PythonCommandScipyOptimizeNewton = "spy.optimize.newton(f, x0)"
+PythonCommandScipySignalSosfilt = "spy.signal.sosfilt(sos, x)"
+PythonCommandScipySignalSpectrogram = "spy.signal.spectrogram(y)"
+PythonCommandScipySpecialErf = "spy.erf(a)"
+PythonCommandScipySpecialErfc = "spy.erfc(a)"
+PythonCommandScipySpecialGamma = "spy.gamma(a)"
+PythonCommandScipySpecialGammaln = "spy.gammaln(a)"
PythonCommandSetPixel = "set_pixel(x,y,color)"
PythonCommandShow = "show()"
PythonCommandSin = "sin(x)"
PythonCommandSinComplex = "sin(z)"
PythonCommandSinh = "sinh(x)"
PythonCommandSleep = "sleep(t)"
+PythonCommandLocalTime = "localtime([timestamp])"
+PythonCommandMktime = "mktime(tm)"
+PythonCommandTime = "time()"
+PythonCommandSetLocaltime = "setlocaltime(tm)"
+PythonCommandRTCmode = "rtcmode()"
+PythonCommandSetRTCmode = "setrtcmode(mode)"
PythonCommandSort = "list.sort()"
PythonCommandSortWithoutArg = ".sort()"
PythonCommandSorted = "sorted(list)"
@@ -222,6 +392,14 @@ PythonOsCommandRename = "rename(oldname, newname)"
PythonOsCommandRemoveWithoutArg = "remove(\x11)"
PythonOsCommandRenameWithoutArg = "rename(\x11,)"
PythonOsCommandListdir = "listdir()"
+PythonSysCommandExit = "exit()"
+PythonSysCommandPrintexception = "print_exception(exc)"
+PythonSysCommandPrintexceptionWithoutArg = "print_exception(\x11)"
+PythonSysCommandByteorder = "byteorder"
+PythonSysCommandImplementation = "implementation"
+PythonSysCommandModules = "modules"
+PythonSysCommandVersion = "version"
+PythonSysCommandVersioninfo = "version_info"
PythonTurtleCommandBackward = "backward(x)"
PythonTurtleCommandCircle = "circle(r)"
PythonTurtleCommandColor = "color('c')"
@@ -239,16 +417,8 @@ PythonTurtleCommandPosition = "position()"
PythonTurtleCommandReset = "reset()"
PythonTurtleCommandRight = "right(a)"
PythonTurtleCommandSetheading = "setheading(a)"
-PythonTurtleCommandSetposition = "setposition(x,[y])"
PythonTurtleCommandShowturtle = "showturtle()"
PythonTurtleCommandSpeed = "speed(x)"
-PythonTurtleCommandWhite = "'white'"
-PythonTurtleCommandYellow = "'yellow'"
-PythonTimeModule = "time"
-PythonTimeCommandImportFrom = "from time import *"
-PythonTimeCommandSleep = "sleep()"
-PythonTimeCommandSleepDemo = "sleep(n)"
-PythonTimeCommandMonotonic = "monotonic()"
PythonCommandFileOpen = "open(name, [mode])"
PythonCommandFileOpenWithoutArg = "open(\x11)"
PythonCommandFileSeek = "file.seek(offset, [whence])"
diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp
index ffc2a77685b..257398ae580 100644
--- a/apps/code/editor_controller.cpp
+++ b/apps/code/editor_controller.cpp
@@ -4,6 +4,8 @@
#include "app.h"
#include
#include
+#include "../global_preferences.h"
+#include
using namespace Shared;
@@ -71,6 +73,10 @@ void EditorController::viewDidDisappear() {
m_menuController->scriptContentEditionDidFinish();
}
+void EditorController::textAreaDidReceiveNoneXNTEvent() {
+ AppsContainer::sharedAppsContainer()->resetXNT();
+}
+
bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) {
if (App::app()->textInputDidReceiveEvent(textArea, event)) {
return true;
@@ -80,7 +86,6 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
return true;
}
-
if (event == Ion::Events::Backspace && textArea->selectionIsEmpty()) {
/* If the cursor is on the left of the text of a line, backspace one
* indentation space at a time. */
diff --git a/apps/code/editor_controller.h b/apps/code/editor_controller.h
index 4cd32c1edc8..42b35bfa7af 100644
--- a/apps/code/editor_controller.h
+++ b/apps/code/editor_controller.h
@@ -30,6 +30,7 @@ class EditorController : public ViewController, public TextAreaDelegate, public
TELEMETRY_ID("Editor");
/* TextAreaDelegate */
+ void textAreaDidReceiveNoneXNTEvent() override;
bool textAreaDidReceiveEvent(TextArea * textArea, Ion::Events::Event event) override;
/* InputEventHandlerDelegate */
diff --git a/apps/code/editor_view.cpp b/apps/code/editor_view.cpp
index 2541612d5be..1e3c34af9a0 100644
--- a/apps/code/editor_view.cpp
+++ b/apps/code/editor_view.cpp
@@ -26,7 +26,9 @@ void EditorView::resetSelection() {
}
void EditorView::scrollViewDidChangeOffset(ScrollViewDataSource * scrollViewDataSource) {
- m_gutterView.setOffset(scrollViewDataSource->offset().y());
+ if (m_gutterView.setOffsetAndNeedResize(scrollViewDataSource->offset().y())) {
+ internalLayoutSubviews(true);
+ }
}
View * EditorView::subviewAtIndex(int index) {
@@ -42,8 +44,12 @@ void EditorView::didBecomeFirstResponder() {
}
void EditorView::layoutSubviews(bool force) {
- m_gutterView.setOffset(0);
- KDCoordinate gutterWidth = m_gutterView.minimalSizeForOptimalDisplay().width();
+ m_gutterView.setOffsetAndNeedResize(0); // Whatever the return is, we layout the editor view
+ internalLayoutSubviews(force);
+}
+
+void EditorView::internalLayoutSubviews(bool force) {
+ KDCoordinate gutterWidth = m_gutterView.computeWidth();
m_gutterView.setFrame(KDRect(0, 0, gutterWidth, bounds().height()), force);
m_textArea.setFrame(KDRect(
@@ -67,23 +73,23 @@ void EditorView::GutterView::drawRect(KDContext * ctx, KDRect rect) const {
KDCoordinate firstLine = m_offset / glyphSize.height();
KDCoordinate firstLinePixelOffset = m_offset - firstLine * glyphSize.height();
- char lineNumber[k_lineNumberCharLength];
+ char lineNumberBuffer[m_numberOfDigits + 1];
int numberOfLines = bounds().height() / glyphSize.height() + 1;
for (int i=0; i= 10) {
- line.serialize(lineNumber, k_lineNumberCharLength);
- } else {
- // Add a leading "0"
- lineNumber[0] = '0';
- line.serialize(lineNumber + 1, k_lineNumberCharLength - 1);
+
+ int lineDigits = computeNumberOfDigitsFor(lineNumberValue);
+
+ for (int j=0; j < m_numberOfDigits - lineDigits; j++) {
+ lineNumberBuffer[j] = ' ';
}
- KDCoordinate leftPadding = (2 - strlen(lineNumber)) * glyphSize.width();
+
+ line.serialize(lineNumberBuffer + (m_numberOfDigits - lineDigits), m_numberOfDigits + 1);
+
ctx->drawString(
- lineNumber,
- KDPoint(k_margin + leftPadding, i*glyphSize.height() - firstLinePixelOffset),
+ lineNumberBuffer,
+ KDPoint(k_margin, i*glyphSize.height() - firstLinePixelOffset),
m_font,
textColor,
backgroundColor
@@ -91,18 +97,36 @@ void EditorView::GutterView::drawRect(KDContext * ctx, KDRect rect) const {
}
}
-void EditorView::GutterView::setOffset(KDCoordinate offset) {
+bool EditorView::GutterView::setOffsetAndNeedResize(KDCoordinate offset) {
if (m_offset == offset) {
- return;
+ return false;
}
m_offset = offset;
+
+ int numberOfDigits = computeMaxNumberOfDigits();
+ if (numberOfDigits != m_numberOfDigits) {
+ m_numberOfDigits = numberOfDigits;
+ return true;
+ }
+
markRectAsDirty(bounds());
+ return false;
}
+int EditorView::GutterView::computeWidth() {
+ return 2 * k_margin + (m_numberOfDigits) * m_font->glyphSize().width();
+}
-KDSize EditorView::GutterView::minimalSizeForOptimalDisplay() const {
- int numberOfChars = 2; // TODO: Could be computed
- return KDSize(2 * k_margin + numberOfChars * Poincare::Preferences::sharedPreferences()->KDPythonFont()->glyphSize().width(), 0);
+int EditorView::GutterView::computeMaxNumberOfDigits() {
+ return computeNumberOfDigitsFor((bounds().height() / m_font->glyphSize().height() + 1) + (m_offset / m_font->glyphSize().height()));
+}
+
+int EditorView::GutterView::computeNumberOfDigitsFor(int value) {
+ int digits = 1;
+ while (value >= pow(10, digits)) {
+ digits++;
+ }
+ return digits;
}
}
diff --git a/apps/code/editor_view.h b/apps/code/editor_view.h
index 547f7340b53..6c91fdde617 100644
--- a/apps/code/editor_view.h
+++ b/apps/code/editor_view.h
@@ -29,6 +29,7 @@ class EditorView : public Responder, public View, public ScrollViewDelegate {
void unloadSyntaxHighlighter() { m_textArea.unloadSyntaxHighlighter(); };
void scrollViewDidChangeOffset(ScrollViewDataSource * scrollViewDataSource) override;
void didBecomeFirstResponder() override;
+ void internalLayoutSubviews(bool force);
private:
int numberOfSubviews() const override { return 2; }
View * subviewAtIndex(int index) override;
@@ -36,15 +37,21 @@ class EditorView : public Responder, public View, public ScrollViewDelegate {
class GutterView : public View {
public:
- GutterView(const KDFont * font) : View(), m_font(font), m_offset(0) {}
+ GutterView(const KDFont * font) : View(), m_font(font), m_offset(0), m_numberOfDigits(2) {}
+
void drawRect(KDContext * ctx, KDRect rect) const override;
- void setOffset(KDCoordinate offset);
- KDSize minimalSizeForOptimalDisplay() const override;
+ bool setOffsetAndNeedResize(KDCoordinate offset); // Return true if the gutter view need to be resized
+
+ int computeWidth();
+ int computeMaxNumberOfDigits();
+ static int computeNumberOfDigitsFor(int value);
+
private:
static constexpr KDCoordinate k_margin = 2;
- static constexpr int k_lineNumberCharLength = 3;
+
const KDFont * m_font;
KDCoordinate m_offset;
+ int m_numberOfDigits;
};
PythonTextArea m_textArea;
diff --git a/apps/code/helpers.cpp b/apps/code/helpers.cpp
index 18250e77f47..7a74f724bb5 100644
--- a/apps/code/helpers.cpp
+++ b/apps/code/helpers.cpp
@@ -10,9 +10,6 @@ const char * PythonTextForEvent(Ion::Events::Event event) {
if (event.text() == pair.firstString()) {
return pair.secondString();
}
- if (event == Ion::Events::XNT) {
- return "x";
- }
}
return nullptr;
}
diff --git a/apps/code/menu_controller.cpp b/apps/code/menu_controller.cpp
index a857fc539a2..63a50c0a882 100644
--- a/apps/code/menu_controller.cpp
+++ b/apps/code/menu_controller.cpp
@@ -90,6 +90,11 @@ bool MenuController::handleEvent(Ion::Events::Event event) {
footer()->setSelectedButton(0);
return true;
}
+ if (event == Ion::Events::ShiftBack) {
+ Ion::Storage::sharedStorage()->reinsertTrash("py");
+ m_selectableTableView.reloadData();
+ return true;
+ }
if (event == Ion::Events::Up) {
if (footer()->selectedButton() == 0) {
footer()->setSelectedButton(-1);
diff --git a/apps/code/python_text_area.cpp b/apps/code/python_text_area.cpp
index ab0615f3bf4..3edf9eeae8f 100644
--- a/apps/code/python_text_area.cpp
+++ b/apps/code/python_text_area.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include "../global_preferences.h"
extern "C" {
#include "py/nlr.h"
@@ -23,7 +24,20 @@ constexpr KDColor BackgroundColor = Palette::CodeBackground;
constexpr KDColor HighlightColor = Palette::CodeBackgroundSelected;
constexpr KDColor AutocompleteColor = KDColor::RGB24(0xC6C6C6); // TODO Palette change
+bool isItalic(mp_token_kind_t tokenKind) {
+ if (!GlobalPreferences::sharedGlobalPreferences()->syntaxhighlighting()) {
+ return false;
+ }
+ if (tokenKind == MP_TOKEN_STRING) {
+ return true;
+ }
+ return false;
+}
+
static inline KDColor TokenColor(mp_token_kind_t tokenKind) {
+ if (!GlobalPreferences::sharedGlobalPreferences()->syntaxhighlighting()) {
+ return Palette::CodeText;
+ }
if (tokenKind == MP_TOKEN_STRING) {
return StringColor;
}
@@ -65,7 +79,8 @@ static inline KDColor TokenColor(mp_token_kind_t tokenKind) {
&& MP_TOKEN_KW_TRY + 1 == MP_TOKEN_KW_WHILE
&& MP_TOKEN_KW_WHILE + 1 == MP_TOKEN_KW_WITH
&& MP_TOKEN_KW_WITH + 1 == MP_TOKEN_KW_YIELD
- && MP_TOKEN_KW_YIELD + 1 == MP_TOKEN_OP_TILDE,
+ && MP_TOKEN_KW_YIELD + 1 == MP_TOKEN_OP_ASSIGN
+ && MP_TOKEN_OP_ASSIGN + 1 == MP_TOKEN_OP_TILDE,
"MP_TOKEN order changed, so Code::PythonTextArea::TokenColor might need to change too.");
if (tokenKind >= MP_TOKEN_KW_FALSE && tokenKind <= MP_TOKEN_KW_YIELD) {
return KeywordColor;
@@ -118,7 +133,8 @@ static inline KDColor TokenColor(mp_token_kind_t tokenKind) {
if ((tokenKind >= MP_TOKEN_OP_TILDE && tokenKind <= MP_TOKEN_DEL_DBL_STAR_EQUAL)
|| tokenKind == MP_TOKEN_DEL_EQUAL
- || tokenKind == MP_TOKEN_DEL_MINUS_MORE)
+ || tokenKind == MP_TOKEN_DEL_MINUS_MORE
+ || tokenKind == MP_TOKEN_OP_ASSIGN)
{
return OperatorColor;
}
@@ -156,7 +172,7 @@ PythonTextArea::AutocompletionType PythonTextArea::autocompletionType(const char
const char * tokenEnd;
_mp_token_kind_t currentTokenKind = lex->tok_kind;
- while (currentTokenKind != MP_TOKEN_NEWLINE && currentTokenKind != MP_TOKEN_END) {
+ while (currentTokenKind != MP_TOKEN_NEWLINE && currentTokenKind != MP_TOKEN_END && currentTokenKind != MP_TOKEN_FSTRING_RAW) {
tokenStart = firstNonSpace + lex->tok_column - 1;
tokenEnd = tokenStart + TokenLength(lex, tokenStart);
@@ -249,7 +265,8 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
BackgroundColor,
selectionStart,
selectionEnd,
- HighlightColor);
+ HighlightColor,
+ false);
}
if (UTF8Helper::CodePointIs(firstNonSpace, UCodePointNull)) {
return;
@@ -265,7 +282,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
const char * tokenFrom = firstNonSpace;
size_t tokenLength = 0;
const char * tokenEnd = firstNonSpace;
- while (lex->tok_kind != MP_TOKEN_NEWLINE && lex->tok_kind != MP_TOKEN_END) {
+ while (lex->tok_kind != MP_TOKEN_NEWLINE && lex->tok_kind != MP_TOKEN_END && lex->tok_kind != MP_TOKEN_FSTRING_RAW) {
tokenFrom = firstNonSpace + lex->tok_column - 1;
if (tokenFrom != tokenEnd) {
// We passed over white spaces, we need to color them
@@ -279,13 +296,15 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
BackgroundColor,
selectionStart,
selectionEnd,
- HighlightColor);
+ HighlightColor,
+ false);
}
tokenLength = TokenLength(lex, tokenFrom);
tokenEnd = tokenFrom + tokenLength;
- // If the token is being autocompleted, use DefaultColor
+ // If the token is being autocompleted, use DefaultColor/Font
KDColor color = (tokenFrom <= autocompleteStart && autocompleteStart < tokenEnd) ? Palette::CodeText : TokenColor(lex->tok_kind);
+ bool italic = (tokenFrom <= autocompleteStart && autocompleteStart < tokenEnd) ? false : isItalic(lex->tok_kind);
LOG_DRAW("Draw \"%.*s\" for token %d\n", tokenLength, tokenFrom, lex->tok_kind);
drawStringAt(ctx, line,
@@ -296,7 +315,9 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
BackgroundColor,
selectionStart,
selectionEnd,
- HighlightColor);
+ HighlightColor,
+ italic
+ );
mp_lexer_to_next(lex);
LOG_DRAW("Pop token %d\n", lex->tok_kind);
@@ -304,6 +325,10 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
tokenFrom += tokenLength;
+ KDColor color = CommentColor;
+ if (!GlobalPreferences::sharedGlobalPreferences()->syntaxhighlighting()) {
+ color = Palette::CodeText;
+ }
// Even if the token is being autocompleted, use CommentColor
if (tokenFrom < text + byteLength) {
LOG_DRAW("Draw comment \"%.*s\" from %d\n", byteLength - (tokenFrom - text), firstNonSpace, tokenFrom);
@@ -311,11 +336,12 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
UTF8Helper::GlyphOffsetAtCodePoint(text, tokenFrom),
tokenFrom,
text + byteLength - tokenFrom,
- CommentColor,
+ color,
BackgroundColor,
selectionStart,
selectionEnd,
- HighlightColor);
+ HighlightColor,
+ true);
}
mp_lexer_free(lex);
@@ -335,7 +361,8 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
BackgroundColor,
nullptr,
nullptr,
- HighlightColor);
+ HighlightColor,
+ false);
}
}
@@ -399,14 +426,14 @@ bool PythonTextArea::handleEvent(Ion::Events::Event event) {
return result;
}
-bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
+bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText, bool shouldRemoveLastCharacter) {
if (*text == 0) {
return false;
}
if (m_contentView.isAutocompleting()) {
removeAutocompletion();
}
- bool result = TextArea::handleEventWithText(text, indentation, forceCursorRightOfText);
+ bool result = TextArea::handleEventWithText(text, indentation, forceCursorRightOfText, shouldRemoveLastCharacter);
addAutocompletion();
return result;
}
@@ -444,6 +471,11 @@ void PythonTextArea::addAutocompletion() {
}
bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIndexToUpdate) {
+ // If Autocomplete disable, skip this step
+ if(!GlobalPreferences::sharedGlobalPreferences()->autocomplete()) {
+ return false;
+ }
+
// The variable box should be loaded at this point
const char * autocompletionTokenBeginning = nullptr;
const char * autocompletionLocation = const_cast(cursorLocation());
@@ -461,9 +493,10 @@ bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIn
if (textToInsertLength > 0) {
// Try to insert the text (this might fail if the buffer is full)
- if (!m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength)) {
+ if (!m_contentView.isAbleToInsertTextAt(textToInsertLength, autocompletionLocation, false)) {
return false;
}
+ m_contentView.insertTextAtLocation(textToInsert, const_cast(autocompletionLocation), textToInsertLength);
autocompletionLocation += textToInsertLength;
m_contentView.setAutocompleting(true);
m_contentView.setAutocompletionEnd(autocompletionLocation);
@@ -475,7 +508,8 @@ bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIn
assert(strlen(parentheses) == parenthesesLength);
/* If couldInsertText is false, we should not try to add the parentheses as
* there was already not enough space to add the autocompletion. */
- if (addParentheses && m_contentView.insertTextAtLocation(parentheses, const_cast(autocompletionLocation), parenthesesLength)) {
+ if (addParentheses && m_contentView.isAbleToInsertTextAt(parenthesesLength, autocompletionLocation, false)) {
+ m_contentView.insertTextAtLocation(parentheses, const_cast(autocompletionLocation), parenthesesLength);
m_contentView.setAutocompleting(true);
m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength);
return true;
diff --git a/apps/code/python_text_area.h b/apps/code/python_text_area.h
index c1a64db5ffe..57a46a5f85c 100644
--- a/apps/code/python_text_area.h
+++ b/apps/code/python_text_area.h
@@ -23,14 +23,14 @@ class PythonTextArea : public TextArea {
void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); }
void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); }
bool handleEvent(Ion::Events::Event event) override;
- bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false) override;
+ bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = false, bool shouldRemoveLastCharacter = false) override;
/* autocompletionType returns:
* - EndOfIdentifier if there is currently autocompletion, or if the cursor is
* at the end of an identifier,
* - MiddleOfIdentifier is the cursor is in the middle of an identifier,
* - No identifier otherwise.
* The autocompletionLocation can be provided with autocompletionLocation, or
- * retreived with autocompletionLocationBeginning and autocompletionLocationEnd. */
+ * retrieved with autocompletionLocationBeginning and autocompletionLocationEnd. */
AutocompletionType autocompletionType(const char * autocompletionLocation = nullptr, const char ** autocompletionLocationBeginning = nullptr, const char ** autocompletionLocationEnd = nullptr) const;
bool isAutocompleting() const { return m_contentView.isAutocompleting(); }
protected:
diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp
index 4adf6279544..f8a74902223 100644
--- a/apps/code/python_toolbox.cpp
+++ b/apps/code/python_toolbox.cpp
@@ -10,22 +10,22 @@ extern "C" {
namespace Code {
const ToolboxMessageTree forLoopChildren[] = {
- ToolboxMessageTree::Leaf(I18n::Message::ForInRange1ArgLoopWithArg, I18n::Message::Default, false, I18n::Message::ForInRange1ArgLoop),
- ToolboxMessageTree::Leaf(I18n::Message::ForInRange2ArgsLoopWithArg, I18n::Message::Default, false, I18n::Message::ForInRange2ArgsLoop),
- ToolboxMessageTree::Leaf(I18n::Message::ForInRange3ArgsLoopWithArg, I18n::Message::Default, false, I18n::Message::ForInRange3ArgsLoop),
- ToolboxMessageTree::Leaf(I18n::Message::ForInListLoopWithArg, I18n::Message::Default, false, I18n::Message::ForInListLoop)
+ ToolboxMessageTree::Leaf(I18n::Message::ForInRange1ArgLoopWithArg, I18n::Message::Default, false, I18n::Message::ForInRange1ArgLoop, true, 2),
+ ToolboxMessageTree::Leaf(I18n::Message::ForInRange2ArgsLoopWithArg, I18n::Message::Default, false, I18n::Message::ForInRange2ArgsLoop, true, 2),
+ ToolboxMessageTree::Leaf(I18n::Message::ForInRange3ArgsLoopWithArg, I18n::Message::Default, false, I18n::Message::ForInRange3ArgsLoop, true, 2),
+ ToolboxMessageTree::Leaf(I18n::Message::ForInListLoopWithArg, I18n::Message::Default, false, I18n::Message::ForInListLoop, true, 2)
};
const ToolboxMessageTree ifStatementChildren[] = {
- ToolboxMessageTree::Leaf(I18n::Message::IfElseStatementWithArg, I18n::Message::Default, false, I18n::Message::IfElseStatement),
- ToolboxMessageTree::Leaf(I18n::Message::IfThenStatementWithArg, I18n::Message::Default, false, I18n::Message::IfThenStatement),
- ToolboxMessageTree::Leaf(I18n::Message::IfElifElseStatementWithArg, I18n::Message::Default, false, I18n::Message::IfElifElseStatement),
- ToolboxMessageTree::Leaf(I18n::Message::IfAndIfElseStatementWithArg, I18n::Message::Default, false, I18n::Message::IfAndIfElseStatement),
- ToolboxMessageTree::Leaf(I18n::Message::IfOrIfElseStatementWithArg, I18n::Message::Default, false, I18n::Message::IfOrIfElseStatement)
+ ToolboxMessageTree::Leaf(I18n::Message::IfElseStatementWithArg, I18n::Message::Default, false, I18n::Message::IfElseStatement, true, 4),
+ ToolboxMessageTree::Leaf(I18n::Message::IfThenStatementWithArg, I18n::Message::Default, false, I18n::Message::IfThenStatement, true, 2),
+ ToolboxMessageTree::Leaf(I18n::Message::IfElifElseStatementWithArg, I18n::Message::Default, false, I18n::Message::IfElifElseStatement, true, 6),
+ ToolboxMessageTree::Leaf(I18n::Message::IfAndIfElseStatementWithArg, I18n::Message::Default, false, I18n::Message::IfAndIfElseStatement, true, 4),
+ ToolboxMessageTree::Leaf(I18n::Message::IfOrIfElseStatementWithArg, I18n::Message::Default, false, I18n::Message::IfOrIfElseStatement, true, 4)
};
const ToolboxMessageTree whileLoopChildren[] = {
- ToolboxMessageTree::Leaf(I18n::Message::WhileLoopWithArg, I18n::Message::Default, false, I18n::Message::WhileLoop)
+ ToolboxMessageTree::Leaf(I18n::Message::WhileLoopWithArg, I18n::Message::Default, false, I18n::Message::WhileLoop, true, 2)
};
const ToolboxMessageTree conditionsChildren[] = {
@@ -75,6 +75,7 @@ const ToolboxMessageTree MathModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan2, I18n::Message::PythonAtan2),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCeil, I18n::Message::PythonCeil),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCopySign, I18n::Message::PythonCopySign),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFactorial, I18n::Message::PythonFactorial),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFabs, I18n::Message::PythonFabs),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFloor, I18n::Message::PythonFloor),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFmod, I18n::Message::PythonFmod),
@@ -135,6 +136,184 @@ const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGray, I18n::Message::PythonColorGray, false)
};
+#if defined(INCLUDE_ULAB)
+
+const ToolboxMessageTree NumpyNdarrayModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArray),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArange),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyConcatenate),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDiag),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyZeros),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyOnes),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEmpty),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEye),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFull),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLinspace),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLogspace),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFromBuffer),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCopy, I18n::Message::Default, false, I18n::Message::PythonCommandNumpyCopyWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDtype, I18n::Message::Default, false, I18n::Message::PythonCommandNumpyDtypeWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlat, I18n::Message::Default, false, I18n::Message::PythonCommandNumpyFlatWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlatten, I18n::Message::Default, false, I18n::Message::PythonCommandNumpyFlattenWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyShape, I18n::Message::Default, false, I18n::Message::PythonCommandNumpyShapeWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyReshape, I18n::Message::Default, false, I18n::Message::PythonCommandNumpyReshapeWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySize, I18n::Message::Default, false, I18n::Message::PythonCommandNumpySizeWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTranspose, I18n::Message::Default, false, I18n::Message::PythonCommandNumpyTransposeWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySort, I18n::Message::Default, false, I18n::Message::PythonCommandNumpySortWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyToBytes, I18n::Message::Default, false, I18n::Message::PythonCommandNumpyToBytesWithoutArg)
+};
+
+const ToolboxMessageTree NumpyFunctionsModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNdinfo),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAll),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAny),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgmax),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgmin),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgsort),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyClip),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyConvolve),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDiff),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInterp),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDot),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCross),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEqual),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNot_equal),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlip),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIsfinite),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIsinf),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMean),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMin),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMax),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMedian),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMinimum),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMaximum),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPolyfit),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPolyval),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyRoll),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySortWithArguments),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyStd),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySum),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTrace),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTrapz),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyWhere),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyVectorize),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAcos),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAcosh),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArctan2),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAround),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAsin),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAsinh),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAtan),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAtanh),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCeil),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCos),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCosh),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDegrees),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyExp),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyExpm1),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFloor),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog10),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog2),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyRadians),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySin),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySinh),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySqrt),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTan),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTanh),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyBool),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFloat),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyUint8),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInt8),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyUint16),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInt16),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNan),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInf),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyE),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPi),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySetPrintOptions),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyGetPrintOptions)
+};
+
+const ToolboxMessageTree NumpyFftModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFftFunction, I18n::Message::PythonNumpyFftFunction, false, I18n::Message::PythonCommandNumpyFftFunctionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFft),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIfft)
+};
+
+const ToolboxMessageTree NumpyLinalgModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLinalgFunction, I18n::Message::PythonNumpyLinalgFunction, false, I18n::Message::PythonCommandNumpyLinalgFunctionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDet),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEig),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCholesky),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInv),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNorm)
+};
+
+const ToolboxMessageTree NumpyModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromNumpy, I18n::Message::PythonImportNumpy, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFunction, I18n::Message::PythonNumpyFunction, false, I18n::Message::PythonCommandNumpyFunctionWithoutArg),
+ ToolboxMessageTree::Node(I18n::Message::NumpyNdarray, NumpyNdarrayModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::Functions, NumpyFunctionsModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::NumpyFftModule, NumpyFftModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::NumpyLinalgModule, NumpyLinalgModuleChildren)
+};
+
+const ToolboxMessageTree ScipyLinalgModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyLinalgFunction, I18n::Message::PythonScipyLinalgFunction, false, I18n::Message::PythonCommandScipyLinalgFunctionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyLinalgChoSolve),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyLinalgSolveTriangular)
+};
+
+const ToolboxMessageTree ScipyOptimizeModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyOptimizeFunction, I18n::Message::PythonScipyOptimizeFunction, false, I18n::Message::PythonCommandScipyOptimizeFunctionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyOptimizeBisect),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyOptimizeFmin),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyOptimizeNewton)
+};
+
+const ToolboxMessageTree ScipySignalModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySignalFunction, I18n::Message::PythonScipySignalFunction, false, I18n::Message::PythonCommandScipySignalFunctionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySignalSosfilt),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySignalSpectrogram)
+};
+
+const ToolboxMessageTree ScipySpecialModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialFunction, I18n::Message::PythonScipySpecialFunction, false, I18n::Message::PythonCommandScipySpecialFunctionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialErf),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialErfc),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialGamma),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialGammaln),
+};
+
+const ToolboxMessageTree ScipyModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromScipy, I18n::Message::PythonImportScipy, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyFunction, I18n::Message::PythonScipyFunction, false, I18n::Message::PythonCommandScipyFunctionWithoutArg),
+ ToolboxMessageTree::Node(I18n::Message::ScipyLinalgModule, ScipyLinalgModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::ScipyOptimizeModule, ScipyOptimizeModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::ScipySignalModule, ScipySignalModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::ScipySpecialModule, ScipySpecialModuleChildren),
+};
+
+const ToolboxMessageTree UtilsModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromUtils, I18n::Message::PythonImportUtils, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUtilsFunction, I18n::Message::PythonUtilsFunction, false, I18n::Message::PythonCommandUtilsFunctionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUtilsSpectrogram),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUtilsFromInt16Buffer),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUtilsFromUint16Buffer),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUtilsFromInt32Buffer),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUtilsFromUint32Buffer),
+};
+
+const ToolboxMessageTree UlabModuleChildren[] = {
+ ToolboxMessageTree::Node(I18n::Message::NumpyModule, NumpyModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::ScipyModule, ScipyModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::UtilsModule, UtilsModuleChildren),
+ ToolboxMessageTree::Leaf(I18n::Message::UlabDocumentation, I18n::Message::UlabDocumentationLink)
+};
+
+#endif
+
const ToolboxMessageTree TurtleModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false),
@@ -194,7 +373,60 @@ const ToolboxMessageTree KandinskyModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawLine, I18n::Message::PythonDrawLine),
- ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect)
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawCircle, I18n::Message::PythonDrawCircle),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillCircle, I18n::Message::PythonFillCircle),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillPolygon, I18n::Message::PythonFillPolygon),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPalette, I18n::Message::PythonGetPalette)
+};
+
+const ToolboxMessageTree IonKeyModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyLeft, I18n::Message::PythonKeyLeft, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyUp, I18n::Message::PythonKeyUp, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyDown, I18n::Message::PythonKeyDown, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyRight, I18n::Message::PythonKeyRight, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyOk, I18n::Message::PythonKeyOk, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyBack, I18n::Message::PythonKeyBack, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyHome, I18n::Message::PythonKeyHome, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyOnOff, I18n::Message::PythonKeyOnOff, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyShift, I18n::Message::PythonKeyShift, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyAlpha, I18n::Message::PythonKeyAlpha, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyXnt, I18n::Message::PythonKeyXnt, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyVar, I18n::Message::PythonKeyVar, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyToolbox, I18n::Message::PythonKeyToolbox, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyBackspace, I18n::Message::PythonKeyBackspace, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyExp, I18n::Message::PythonKeyExp, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyLn, I18n::Message::PythonKeyLn, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyLog, I18n::Message::PythonKeyLog, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyImaginary, I18n::Message::PythonKeyImaginary, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyComma, I18n::Message::PythonKeyComma, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyPower, I18n::Message::PythonKeyPower, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeySine, I18n::Message::PythonKeySine, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyCosine, I18n::Message::PythonKeyCosine, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyTangent, I18n::Message::PythonKeyTangent, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyPi, I18n::Message::PythonKeyPi, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeySqrt, I18n::Message::PythonKeySqrt, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeySquare, I18n::Message::PythonKeySquare, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeySeven, I18n::Message::PythonKeySeven, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyEight, I18n::Message::PythonKeyEight, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyNine, I18n::Message::PythonKeyNine, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyLeftParenthesis, I18n::Message::PythonKeyLeftParenthesis, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyRightParenthesis, I18n::Message::PythonKeyRightParenthesis, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyFour, I18n::Message::PythonKeyFour, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyFive, I18n::Message::PythonKeyFive, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeySix, I18n::Message::PythonKeySix, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyMultiplication, I18n::Message::PythonKeyMultiplication, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyDivision, I18n::Message::PythonKeyDivision, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyOne, I18n::Message::PythonKeyOne, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyTwo, I18n::Message::PythonKeyTwo, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyThree, I18n::Message::PythonKeyThree, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyPlus, I18n::Message::PythonKeyPlus, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyMinus, I18n::Message::PythonKeyMinus, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyZero, I18n::Message::PythonKeyZero, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyDot, I18n::Message::PythonKeyDot, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyEe, I18n::Message::PythonKeyEe, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyAns, I18n::Message::PythonKeyAns, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKeyExe, I18n::Message::PythonKeyExe, false)
};
const ToolboxMessageTree IonModuleChildren[] = {
@@ -202,15 +434,29 @@ const ToolboxMessageTree IonModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIonFunction, I18n::Message::PythonIonFunction, false, I18n::Message::PythonCommandIonFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIsKeyDown, I18n::Message::PythonIsKeyDown),
- ToolboxMessageTree::Leaf(I18n::Message::IonSelector, I18n::Message::IonSelector)
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetKeys, I18n::Message::PythonGetKeys),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBattery, I18n::Message::PythonBattery),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBatteryLevel, I18n::Message::PythonBatteryLevel),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBatteryIscharging, I18n::Message::PythonBatteryIscharging),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetBrightness, I18n::Message::PythonSetBrightness),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetBrightness, I18n::Message::PythonGetBrightness),
+ // This is a special case, because it is handled separately, so the sub-tree is unused.
+ ToolboxMessageTree::Node(I18n::Message::IonSelector, IonKeyModuleChildren),
+ ToolboxMessageTree::Node(I18n::Message::IonKeyList, IonKeyModuleChildren)
};
const ToolboxMessageTree TimeModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTime, I18n::Message::PythonImportTime, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTime, I18n::Message::PythonImportTime, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTimeFunction, I18n::Message::PythonTimeFunction, false, I18n::Message::PythonCommandTimeFunctionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTime, I18n::Message::PythonTime),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMonotonic, I18n::Message::PythonMonotonic, false),
- ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSleep, I18n::Message::PythonSleep)
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSleep, I18n::Message::PythonSleep),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLocalTime, I18n::Message::PythonLocalTime),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMktime, I18n::Message::PythonMktime),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetLocaltime, I18n::Message::PythonSetLocaltime),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRTCmode, I18n::Message::PythonRTCmode),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetRTCmode, I18n::Message::PythonSetRTCmode),
};
const ToolboxMessageTree OsModuleChildren[] = {
@@ -223,20 +469,49 @@ const ToolboxMessageTree OsModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonOsCommandListdir, I18n::Message::PythonOsListdir, false)
};
+#if MICROPY_PY_SYS
+const ToolboxMessageTree SysModuleChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportSys, I18n::Message::PythonImportSys, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromSys, I18n::Message::PythonImportSys, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonSysCommandExit, I18n::Message::PythonSysExit, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonSysCommandPrintexception, I18n::Message::PythonSysPrintexception, false, I18n::Message::PythonSysCommandPrintexceptionWithoutArg),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonSysCommandByteorder, I18n::Message::PythonSysByteorder, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonSysCommandImplementation, I18n::Message::PythonSysImplementation, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonSysCommandModules, I18n::Message::PythonSysModules, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonSysCommandVersion, I18n::Message::PythonSysVersion, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonSysCommandVersioninfo, I18n::Message::PythonSysVersioninfo, false)
+};
+#endif
+
const ToolboxMessageTree modulesChildren[] = {
ToolboxMessageTree::Node(I18n::Message::MathModule, MathModuleChildren),
ToolboxMessageTree::Node(I18n::Message::CmathModule, CMathModuleChildren),
ToolboxMessageTree::Node(I18n::Message::MatplotlibPyplotModule, MatplotlibPyplotModuleChildren),
+#if defined(INCLUDE_ULAB)
+ ToolboxMessageTree::Node(I18n::Message::UlabModule, UlabModuleChildren),
+#endif
ToolboxMessageTree::Node(I18n::Message::TurtleModule, TurtleModuleChildren),
ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren),
ToolboxMessageTree::Node(I18n::Message::KandinskyModule, KandinskyModuleChildren),
ToolboxMessageTree::Node(I18n::Message::IonModule, IonModuleChildren),
ToolboxMessageTree::Node(I18n::Message::OsModule, OsModuleChildren),
+#if MICROPY_PY_SYS
+ ToolboxMessageTree::Node(I18n::Message::SysModule, SysModuleChildren),
+#endif
ToolboxMessageTree::Node(I18n::Message::TimeModule, TimeModuleChildren)
};
const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPound, I18n::Message::PythonPound, false),
+ #ifdef _FXCG
+ // There is no question mark button on the fx-CG calculators
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColon, I18n::Message::PythonColon, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSemicon, I18n::Message::PythonSemicon, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandExclamationMark, I18n::Message::PythonExclamationMark, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLessThan, I18n::Message::PythonLessThan, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGreaterThan, I18n::Message::PythonGreaterThan, false),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandQuestionMark, I18n::Message::PythonQuestionMark, false),
+ #endif
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPercent, I18n::Message::PythonPercent, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommand1J, I18n::Message::Python1J, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLF, I18n::Message::PythonLF, false),
@@ -273,6 +548,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCosh, I18n::Message::PythonCosh),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDegrees, I18n::Message::PythonDegrees),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDivMod, I18n::Message::PythonDivMod),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawCircle, I18n::Message::PythonDrawCircle),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawLine, I18n::Message::PythonDrawLine),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandConstantE, I18n::Message::PythonConstantE, false),
@@ -282,6 +558,8 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandExp, I18n::Message::PythonExp),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandExpm1, I18n::Message::PythonExpm1),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFabs, I18n::Message::PythonFabs),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillCircle, I18n::Message::PythonFillCircle),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillPolygon, I18n::Message::PythonFillPolygon),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFloat, I18n::Message::PythonFloat),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFloor, I18n::Message::PythonFloor),
@@ -324,6 +602,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIsNaN, I18n::Message::PythonIsNaN),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandIsKeyDown, I18n::Message::PythonIsKeyDown),
+ ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBattery, I18n::Message::PythonBattery),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLdexp, I18n::Message::PythonLdexp),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandLeft, I18n::Message::PythonTurtleLeft),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLength, I18n::Message::PythonLength),
@@ -424,10 +703,10 @@ const ToolboxMessageTree fileChildren[] {
};
const ToolboxMessageTree exceptionsChildren[] = {
- ToolboxMessageTree::Leaf(I18n::Message::TryExcept1ErrorWithArg, I18n::Message::Default, false, I18n::Message::TryExcept1Error),
- ToolboxMessageTree::Leaf(I18n::Message::TryExcept1ErrorElseWithArg, I18n::Message::Default, false, I18n::Message::TryExcept1ErrorElse),
- ToolboxMessageTree::Leaf(I18n::Message::TryExcept2ErrorWithArg, I18n::Message::Default, false, I18n::Message::TryExcept2Error),
- ToolboxMessageTree::Leaf(I18n::Message::WithInstructionWithArg, I18n::Message::Default, false, I18n::Message::WithInstruction),
+ ToolboxMessageTree::Leaf(I18n::Message::TryExcept1ErrorWithArg, I18n::Message::Default, false, I18n::Message::TryExcept1Error, true, 4),
+ ToolboxMessageTree::Leaf(I18n::Message::TryExcept1ErrorElseWithArg, I18n::Message::Default, false, I18n::Message::TryExcept1ErrorElse, true, 6),
+ ToolboxMessageTree::Leaf(I18n::Message::TryExcept2ErrorWithArg, I18n::Message::Default, false, I18n::Message::TryExcept2Error, true, 4),
+ ToolboxMessageTree::Leaf(I18n::Message::WithInstructionWithArg, I18n::Message::Default, false, I18n::Message::WithInstruction, true, 2),
};
const ToolboxMessageTree menu[] = {
@@ -445,6 +724,10 @@ const ToolboxMessageTree toolboxModel = ToolboxMessageTree::Node(I18n::Message::
PythonToolbox::PythonToolbox() :
Toolbox(nullptr, rootModel()->label())
{
+ for (int i=0; i < k_maxNumberOfDisplayedRows; i++) {
+ m_leafCells[i].setMessageFont(KDFont::LargeFont);
+ m_nodeCells[i].setMessageFont(KDFont::LargeFont);
+ }
}
const ToolboxMessageTree * PythonToolbox::moduleChildren(const char * name, int * numberOfNodes) const {
@@ -475,31 +758,28 @@ bool PythonToolbox::handleEvent(Ion::Events::Event event) {
return false;
}
+void PythonToolbox::willDisplayCellForIndex(HighlightCell * cell, int index) {
+ Toolbox::willDisplayCellForIndex(cell, index);
+ const ToolboxMessageTree * messageTree = static_cast(m_messageTreeModel->childAtIndex(index));
+ MessageTableCell * myCell = static_cast *>(cell);
+ myCell->setMessageFont(messageTree->isMultiLine() ? KDFont::SmallFont : KDFont::LargeFont);
+}
+
KDCoordinate PythonToolbox::rowHeight(int j) {
- if (typeAtLocation(0, j) == Toolbox::LeafCellType && (m_messageTreeModel->label() == I18n::Message::IfStatementMenu || m_messageTreeModel->label() == I18n::Message::Exceptions)) {
- /* To get the exact height needed for each cell, we have to compute its
- * text size, which means scan the text char by char to look for '\n'
- * chars. This is very costly and ruins the speed performance when
- * scrolling at the bottom of a long table: to compute a position on the
- * kth row, we call cumulatedHeightFromIndex(k), which calls rowHeight k
- * times.
- * We thus decided to compute the real height only for the ifStatement
- * children of the toolbox, which is the only menu that has special height
- * rows. */
- const ToolboxMessageTree * messageTree = static_cast(m_messageTreeModel->childAtIndex(j));
- return k_font->stringSize(I18n::translate(messageTree->label())).height() + 2*Metric::TableCellVerticalMargin + (messageTree->text() == I18n::Message::Default ? 0 : Toolbox::rowHeight(j));
+ const ToolboxMessageTree * messageTree = static_cast(m_messageTreeModel->childAtIndex(j));
+ if (messageTree->isMultiLine()) {
+ return k_fontForMultiLine->glyphSize().height() * messageTree->numberOfLines() + 2*Metric::TableCellVerticalMargin + (messageTree->text() == I18n::Message::Default ? 0 : Toolbox::rowHeight(j));
}
return Toolbox::rowHeight(j);
}
-bool PythonToolbox::selectLeaf(int selectedRow) {
- m_selectableTableView.deselectTable();
+bool PythonToolbox::selectLeaf(int selectedRow, bool quitToolbox) {
ToolboxMessageTree * node = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(selectedRow);
- if(node->insertedText() == I18n::Message::IonSelector){
- m_ionKeys.setSender(sender());
- Container::activeApp()->displayModalViewController(static_cast(&m_ionKeys), 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
+#if defined(INCLUDE_ULAB)
+ if(node->text() == I18n::Message::UlabDocumentationLink){
return true;
}
+#endif
const char * editedText = I18n::translate(node->insertedText());
// strippedEditedText array needs to be in the same scope as editedText
char strippedEditedText[k_maxMessageSize];
@@ -510,20 +790,35 @@ bool PythonToolbox::selectLeaf(int selectedRow) {
editedText = strippedEditedText;
}
sender()->handleEventWithText(editedText, true);
- Container::activeApp()->dismissModalViewController();
+ if (quitToolbox) {
+ m_selectableTableView.deselectTable();
+ Container::activeApp()->dismissModalViewController();
+ }
return true;
}
+// This is the same function as in the Toolbox class, but we need to override it because we need to handle the Key selector differently.
+bool PythonToolbox::selectSubMenu(int selectedRow) {
+ // If the selected row is a is the Key selector, we display the IonKeySelectorViewController
+ if (m_messageTreeModel->childAtIndex(selectedRow)->label() == I18n::Message::IonSelector) {
+ m_ionKeys.setSender(sender());
+ Container::activeApp()->displayModalViewController(static_cast(&m_ionKeys), 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin);
+ return true;
+ }
+ return Toolbox::selectSubMenu(selectedRow);
+}
+
+
const ToolboxMessageTree * PythonToolbox::rootModel() const {
return &toolboxModel;
}
-MessageTableCellWithMessage * PythonToolbox::leafCellAtIndex(int index) {
+MessageTableCellWithMessage * PythonToolbox::leafCellAtIndex(int index) {
assert(index >= 0 && index < k_maxNumberOfDisplayedRows);
return &m_leafCells[index];
}
-MessageTableCellWithChevron* PythonToolbox::nodeCellAtIndex(int index) {
+MessageTableCellWithChevron * PythonToolbox::nodeCellAtIndex(int index) {
assert(index >= 0 && index < k_maxNumberOfDisplayedRows);
return &m_nodeCells[index];
}
diff --git a/apps/code/python_toolbox.h b/apps/code/python_toolbox.h
index 7c66af03f2c..c641536a405 100644
--- a/apps/code/python_toolbox.h
+++ b/apps/code/python_toolbox.h
@@ -18,22 +18,28 @@ class PythonToolbox : public Toolbox {
// Toolbox
bool handleEvent(Ion::Events::Event event) override;
const ToolboxMessageTree * rootModel() const override;
+
+ // ListViewDataSource
+ void willDisplayCellForIndex(HighlightCell * cell, int index) override;
+
protected:
KDCoordinate rowHeight(int j) override;
- bool selectLeaf(int selectedRow) override;
- MessageTableCellWithMessage * leafCellAtIndex(int index) override;
- MessageTableCellWithChevron* nodeCellAtIndex(int index) override;
+ bool selectLeaf(int selectedRow, bool quitToolbox) override;
+ bool selectSubMenu(int selectedRow) override;
+ MessageTableCellWithMessage * leafCellAtIndex(int index) override;
+ MessageTableCellWithChevron * nodeCellAtIndex(int index) override;
int maxNumberOfDisplayedRows() override;
+ bool canStayInMenu() override { return true; }
constexpr static int k_maxNumberOfDisplayedRows = 13; // = 240/(13+2*3)
// 13 = minimal string height size
// 3 = vertical margins
private:
- constexpr static const KDFont * k_font = KDFont::SmallFont;
+ constexpr static const KDFont * k_fontForMultiLine = KDFont::SmallFont;
void scrollToLetter(char letter);
void scrollToAndSelectChild(int i);
- MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows];
- MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows];
- toolboxIonKeys m_ionKeys;
+ MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows];
+ MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows];
+ ToolboxIonKeys m_ionKeys;
};
}
diff --git a/apps/code/script_node_cell.cpp b/apps/code/script_node_cell.cpp
index 0dc8675c359..b51abdf86a4 100644
--- a/apps/code/script_node_cell.cpp
+++ b/apps/code/script_node_cell.cpp
@@ -21,10 +21,10 @@ void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) cons
const int nodeNameLength = m_scriptNode->nameLength();
KDSize nameSize = k_font->stringSize(nodeName, nodeNameLength);
const KDCoordinate nodeNameY = k_topMargin;
- ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, KDColorBlack, backgroundColor, nodeNameLength);
+ ctx->drawString(nodeName, KDPoint(0, nodeNameY), k_font, Palette::PrimaryText, backgroundColor, nodeNameLength);
// If it is needed, draw the parentheses
if (m_scriptNode->type() == ScriptNode::Type::WithParentheses) {
- ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, KDColorBlack, backgroundColor);
+ ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), nodeNameY), k_font, Palette::PrimaryText, backgroundColor);
}
/* If it exists, draw the source name. If it did not fit, we would have put
diff --git a/apps/code/script_parameter_controller.h b/apps/code/script_parameter_controller.h
index e7065e7334f..193879b683c 100644
--- a/apps/code/script_parameter_controller.h
+++ b/apps/code/script_parameter_controller.h
@@ -34,11 +34,11 @@ class ScriptParameterController : public ViewController, public SimpleListViewDa
constexpr static int k_totalNumberOfCell = 6;
StackViewController * stackViewController();
I18n::Message m_pageTitle;
- MessageTableCell m_executeScript;
- MessageTableCell m_renameScript;
+ MessageTableCell<> m_executeScript;
+ MessageTableCell<> m_renameScript;
MessageTableCellWithSwitch m_autoImportScript;
- MessageTableCell m_deleteScript;
- MessageTableCell m_duplicateScript;
+ MessageTableCell<> m_deleteScript;
+ MessageTableCell<> m_duplicateScript;
MessageTableCellWithBuffer m_size;
void GetScriptSize(MessageTableCellWithBuffer* myCell);
SelectableTableView m_selectableTableView;
diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp
index ebc35882753..ad790811b53 100644
--- a/apps/code/script_store.cpp
+++ b/apps/code/script_store.cpp
@@ -8,11 +8,9 @@ bool ScriptStore::ScriptNameIsFree(const char * baseName) {
return ScriptBaseNamed(baseName).isNull();
}
+// Here we add "base" script
ScriptStore::ScriptStore() {
- addScriptFromTemplate(ScriptTemplate::Squares());
- addScriptFromTemplate(ScriptTemplate::Parabola());
- addScriptFromTemplate(ScriptTemplate::Mandelbrot());
- addScriptFromTemplate(ScriptTemplate::Polynomial());
+
}
void ScriptStore::deleteAllScripts() {
diff --git a/apps/code/script_store.h b/apps/code/script_store.h
index ad9b59ff7c1..00beec5d3c7 100644
--- a/apps/code/script_store.h
+++ b/apps/code/script_store.h
@@ -49,7 +49,7 @@ class ScriptStore : public MicroPython::ScriptProvider {
* k_fullFreeSpaceSizeLimit, we consider the script store as full.
* To be able to add a new empty record, the available space should at least
* be able to store a Script with default name and its extension, the
- * importation status (1 char), the default content "from math import *\n"
+ * importation status (1 char), the cursor (2 char), the default content "from math import *\n"
* (20 char) and 10 char of free space. */
static constexpr int k_fullFreeSpaceSizeLimit = sizeof(Ion::Storage::record_size_t)+Script::k_defaultScriptNameMaxSize+k_scriptExtensionLength+1+20+10;
};
diff --git a/apps/code/script_template.cpp b/apps/code/script_template.cpp
index 8b59c912af1..c5bde929ea4 100644
--- a/apps/code/script_template.cpp
+++ b/apps/code/script_template.cpp
@@ -5,103 +5,9 @@ namespace Code {
constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01" R"(from math import *
)");
-constexpr ScriptTemplate squaresScriptTemplate("squares.py", "\x01" R"(from math import *
-from turtle import *
-def squares(angle=0.5):
- reset()
- L=330
- speed(10)
- penup()
- goto(-L/2,-L/2)
- pendown()
- for i in range(660):
- forward(L)
- left(90+angle)
- L=L-L*sin(angle*pi/180)
- hideturtle())");
-
-constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01" R"(# This script draws a Mandelbrot fractal set
-# N_iteration: degree of precision
-import kandinsky
-def mandelbrot(N_iteration):
- for x in range(320):
- for y in range(222):
-# Compute the mandelbrot sequence for the point c = (c_r, c_i) with start value z = (z_r, z_i)
- z = complex(0,0)
-# Rescale to fit the drawing screen 320x222
- c = complex(3.5*x/319-2.5, -2.5*y/221+1.25)
- i = 0
- while (i < N_iteration) and abs(z) < 2:
- i = i + 1
- z = z*z+c
-# Choose the color of the dot from the Mandelbrot sequence
- rgb = int(255*i/N_iteration)
- col = kandinsky.color(int(rgb*0.82),int(rgb*0.13),int(rgb*0.18))
-# Draw a pixel colored in 'col' at position (x,y)
- kandinsky.set_pixel(x,y,col))");
-
-constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from math import *
-# roots(a,b,c) computes the solutions of the equation a*x**2+b*x+c=0
-def roots(a,b,c):
- delta = b*b-4*a*c
- if delta == 0:
- return -b/(2*a)
- elif delta > 0:
- x_1 = (-b-sqrt(delta))/(2*a)
- x_2 = (-b+sqrt(delta))/(2*a)
- return x_1, x_2
- else:
- return None)");
-
-constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import *
-from math import *
-
-g=9.81
-
-def x(t,v_0,alpha):
- return v_0*cos(alpha)*t
-def y(t,v_0,alpha,h_0):
- return -0.5*g*t**2+v_0*sin(alpha)*t+h_0
-
-def vx(v_0,alpha):
- return v_0*cos(alpha)
-def vy(t,v_0,alpha):
- return -g*t+v_0*sin(alpha)
-
-def t_max(v_0,alpha,h_0):
- return (v_0*sin(alpha)+sqrt((v_0**2)*(sin(alpha)**2)+2*g*h_0))/g
-
-def simulation(v_0=15,alpha=pi/4,h_0=2):
- tMax=t_max(v_0,alpha,h_0)
- accuracy=1/10**(floor(log10(tMax))-1)
- T_MAX=floor(tMax*accuracy)+1
- X=[x(t/accuracy,v_0,alpha) for t in range(T_MAX)]
- Y=[y(t/accuracy,v_0,alpha,h_0) for t in range(T_MAX)]
- VX=[vx(v_0,alpha) for t in range(T_MAX)]
- VY=[vy(t/accuracy,v_0,alpha) for t in range(T_MAX)]
- for i in range(T_MAX):
- arrow(X[i],Y[i],VX[i]/accuracy,VY[i]/accuracy)
- grid()
- show())");
const ScriptTemplate * ScriptTemplate::Empty() {
return &emptyScriptTemplate;
}
-const ScriptTemplate * ScriptTemplate::Squares() {
- return &squaresScriptTemplate;
-}
-
-const ScriptTemplate * ScriptTemplate::Mandelbrot() {
- return &mandelbrotScriptTemplate;
-}
-
-const ScriptTemplate * ScriptTemplate::Polynomial() {
- return &polynomialScriptTemplate;
-}
-
-const ScriptTemplate * ScriptTemplate::Parabola() {
- return ¶bolaScriptTemplate;
-}
-
}
diff --git a/apps/code/script_template.h b/apps/code/script_template.h
index ec32e7052a5..6eac56d34b1 100644
--- a/apps/code/script_template.h
+++ b/apps/code/script_template.h
@@ -9,10 +9,6 @@ class ScriptTemplate {
public:
constexpr ScriptTemplate(const char * name, const char * value) : m_name(name), m_value(value) {}
static const ScriptTemplate * Empty();
- static const ScriptTemplate * Squares();
- static const ScriptTemplate * Mandelbrot();
- static const ScriptTemplate * Polynomial();
- static const ScriptTemplate * Parabola();
const char * name() const { return m_name; }
const char * content() const { return m_value + Script::StatusSize(); }
const char * value() const { return m_value; }
diff --git a/apps/code/test/toolbox_ion_keys_dummy.cpp b/apps/code/test/toolbox_ion_keys_dummy.cpp
index 9f38bb541e4..969b20e3c42 100644
--- a/apps/code/test/toolbox_ion_keys_dummy.cpp
+++ b/apps/code/test/toolbox_ion_keys_dummy.cpp
@@ -1,26 +1,26 @@
#include "../toolbox_ion_keys.h"
namespace Code {
- toolboxIonKeys::toolboxIonKeys() :
+ ToolboxIonKeys::ToolboxIonKeys() :
ViewController(nullptr),
m_view()
{
}
- bool toolboxIonKeys::handleEvent(Ion::Events::Event e) {
+ bool ToolboxIonKeys::handleEvent(Ion::Events::Event e) {
return false;
}
- toolboxIonKeys::toolboxIonView::toolboxIonView():
+ ToolboxIonKeys::toolboxIonView::toolboxIonView():
View()
{
}
- void toolboxIonKeys::toolboxIonView::drawRect(KDContext * ctx, KDRect rect) const {
+ void ToolboxIonKeys::toolboxIonView::drawRect(KDContext * ctx, KDRect rect) const {
return;
}
- View * toolboxIonKeys::view(){
+ View * ToolboxIonKeys::view(){
return &m_view;
}
diff --git a/apps/code/test/variable_box_controller.cpp b/apps/code/test/variable_box_controller.cpp
index 2c7e4abfcbe..4dec7e43a1f 100644
--- a/apps/code/test/variable_box_controller.cpp
+++ b/apps/code/test/variable_box_controller.cpp
@@ -40,7 +40,7 @@ void assert_variables_are(const char * script, const char * nameToComplete, cons
&addParentheses,
i,
&index);
- quiz_assert(i == index); // If false, the autompletion has cycled: there are not as many results as expected
+ quiz_assert(i == index); // If false, the autocompletion has cycled: there are not as many results as expected
quiz_assert(strncmp(*(expectedVariables + i), autocompletionI - nameToCompleteLength, textToInsertLength + nameToCompleteLength) == 0);
index++;
}
@@ -63,7 +63,7 @@ QUIZ_CASE(variable_box_controller) {
};
// FIXME This test does not load imported variables for now
assert_variables_are(
- "\x01 from math import *\nfroo=3",
+ "\x01\x01\x01 from math import *\nfroo=3",
"fr",
expectedVariables,
sizeof(expectedVariables) / sizeof(const char *));
diff --git a/apps/code/toolbox.de.i18n b/apps/code/toolbox.de.i18n
index 34840329bfb..c71afcc5254 100644
--- a/apps/code/toolbox.de.i18n
+++ b/apps/code/toolbox.de.i18n
@@ -4,3 +4,7 @@ Modules = "Module"
LoopsAndTests = "Schleifen und Tests"
Files = "Dateien"
Exceptions = "Ausnahmen"
+UlabDocumentation = "Dokumentation"
+IonSelector = "Schlüsselauswahl"
+PressAKey = "drücke eine Taste"
+IonKeyList = "Liste der Schlüssel"
diff --git a/apps/code/toolbox.en.i18n b/apps/code/toolbox.en.i18n
index 81e60c7da2b..820680d2f55 100644
--- a/apps/code/toolbox.en.i18n
+++ b/apps/code/toolbox.en.i18n
@@ -4,3 +4,7 @@ Modules = "Modules"
LoopsAndTests = "Loops and tests"
Files = "Files"
Exceptions = "Exceptions"
+UlabDocumentation = "Documentation"
+IonSelector = "Key selector"
+PressAKey = "Press a key"
+IonKeyList = "List of keys"
diff --git a/apps/code/toolbox.es.i18n b/apps/code/toolbox.es.i18n
index 81e60c7da2b..8744a2872f5 100644
--- a/apps/code/toolbox.es.i18n
+++ b/apps/code/toolbox.es.i18n
@@ -4,3 +4,7 @@ Modules = "Modules"
LoopsAndTests = "Loops and tests"
Files = "Files"
Exceptions = "Exceptions"
+UlabDocumentation = "Documentación"
+IonSelector = "Selector de llave"
+PressAKey = "presione una tecla"
+IonKeyList = "Lista de llaves"
diff --git a/apps/code/toolbox.fr.i18n b/apps/code/toolbox.fr.i18n
index 724abb7a518..b2c2dfe97cf 100644
--- a/apps/code/toolbox.fr.i18n
+++ b/apps/code/toolbox.fr.i18n
@@ -4,3 +4,7 @@ Modules = "Modules"
LoopsAndTests = "Boucles et tests"
Files = "Fichiers"
Exceptions = "Exceptions"
+UlabDocumentation = "Documentation"
+IonSelector = "Sélecteur de touche"
+PressAKey = "Appuyez sur une touche"
+IonKeyList = "Liste des touches"
diff --git a/apps/code/toolbox.hu.i18n b/apps/code/toolbox.hu.i18n
index 89015122024..da82c67b22f 100644
--- a/apps/code/toolbox.hu.i18n
+++ b/apps/code/toolbox.hu.i18n
@@ -4,3 +4,7 @@ Modules = "Modulok"
LoopsAndTests = "Hurkok és tesztek"
Files = "Fájlok"
Exceptions = "Kivételek"
+UlabDocumentation = "Dokumentáció"
+IonSelector = "Kulcsválasztó"
+PressAKey = "Nyomj meg egy gombot"
+IonKeyList = "A kulcsok listája"
diff --git a/apps/code/toolbox.it.i18n b/apps/code/toolbox.it.i18n
index d7b219d872e..fe6546b30c5 100644
--- a/apps/code/toolbox.it.i18n
+++ b/apps/code/toolbox.it.i18n
@@ -2,5 +2,9 @@ Functions = "Funzioni"
Catalog = "Catalogo"
Modules = "Moduli"
LoopsAndTests = "Cicli e test"
-Files = "Files"
-Exceptions = "Exceptions"
+Files = "File"
+Exceptions = "Eccezioni"
+UlabDocumentation = "Documentazione"
+IonSelector = "Selettore tasti"
+PressAKey = "Premi un tasto"
+IonKeyList = "Elenco dei tasti"
diff --git a/apps/code/toolbox.nl.i18n b/apps/code/toolbox.nl.i18n
index 849bd76a6ab..137144df572 100644
--- a/apps/code/toolbox.nl.i18n
+++ b/apps/code/toolbox.nl.i18n
@@ -4,3 +4,7 @@ Modules = "Modules"
LoopsAndTests = "Herhalingen en testen"
Files = "Files"
Exceptions = "Exceptions"
+UlabDocumentation = "Documentatie"
+IonSelector = "Toetsenkiezer"
+PressAKey = "druk op een knop"
+IonKeyList = "Lijst met sleutels"
diff --git a/apps/code/toolbox.pt.i18n b/apps/code/toolbox.pt.i18n
index f7cfad07b03..9884dfdc075 100644
--- a/apps/code/toolbox.pt.i18n
+++ b/apps/code/toolbox.pt.i18n
@@ -4,3 +4,7 @@ Modules = "Módulos"
LoopsAndTests = "Laços e testes"
Files = "Files"
Exceptions = "Exceptions"
+UlabDocumentation = "Documentação"
+IonSelector = "Seletor de chave"
+PressAKey = "Pressione uma tecla"
+IonKeyList = "Lista de chaves"
diff --git a/apps/code/toolbox.universal.i18n b/apps/code/toolbox.universal.i18n
index 4dd5345def6..c05493a0564 100644
--- a/apps/code/toolbox.universal.i18n
+++ b/apps/code/toolbox.universal.i18n
@@ -3,9 +3,21 @@ IonModule = "ion"
KandinskyModule = "kandinsky"
MathModule = "math"
MatplotlibPyplotModule = "matplotlib.pyplot"
+NumpyModule = "numpy"
+NumpyFftModule = "fft"
+NumpyLinalgModule = "linalg"
+ScipyModule = "scipy"
+ScipyLinalgModule = "linalg"
+ScipyOptimizeModule = "optimize"
+ScipySignalModule = "signal"
+ScipySpecialModule = "special"
+NumpyNdarray = "ndarray"
+UtilsModule = "utils"
OsModule = "os"
+SysModule = "sys"
TimeModule = "time"
TurtleModule = "turtle"
+UlabModule = "ulab"
ForLoopMenu = "For"
IfStatementMenu = "If"
WhileLoopMenu = "While"
@@ -57,5 +69,4 @@ PythonCommandDef = "def \x11():\n "
PythonCommandDefWithArg = "def function(x):"
PythonCommandReturn = "return "
RandomModule = "random"
-IonSelector = "Key selector"
-PressAKey = "Press a key"
+UlabDocumentationLink = "micropython-ulab.readthedocs.io"
diff --git a/apps/code/toolbox_ion_keys.cpp b/apps/code/toolbox_ion_keys.cpp
index b3e67f63f04..edfd490aafa 100644
--- a/apps/code/toolbox_ion_keys.cpp
+++ b/apps/code/toolbox_ion_keys.cpp
@@ -6,45 +6,52 @@ extern "C" {
#include
#include
}
-extern const mp_rom_map_elem_t modion_module_globals_table[48];
+extern "C" const mp_rom_map_elem_t modion_module_globals_table[55];
namespace Code {
- toolboxIonKeys::toolboxIonKeys() :
+ToolboxIonKeys::ToolboxIonKeys() :
ViewController(nullptr),
m_view()
- {
- }
+{
+}
- bool toolboxIonKeys::handleEvent(Ion::Events::Event e) {
- Ion::Keyboard::State state = Ion::Keyboard::scan();
- for(uint16_t i = 0; i < sizeof(modion_module_globals_table)/sizeof(_mp_rom_map_elem_t); i++){
- _mp_rom_map_elem_t element = modion_module_globals_table[i];
- if(mp_obj_is_small_int(element.value)){
- int key = mp_obj_get_int(element.value);
- if(state.keyDown(static_cast(key))){
- m_sender->handleEventWithText(qstr_str(MP_OBJ_QSTR_VALUE(element.key)), true);
- }
+bool ToolboxIonKeys::handleEvent(Ion::Events::Event e) {
+ // FIXME: Use event data to get the pressed key and fix the EXE key.
+ Ion::Keyboard::State state = Ion::Keyboard::scan();
+ for (uint16_t i = 0; i < sizeof(modion_module_globals_table) / sizeof(_mp_rom_map_elem_t); i++) {
+ _mp_rom_map_elem_t element = modion_module_globals_table[i];
+ if (mp_obj_is_small_int(element.value)) {
+ int key = mp_obj_get_int(element.value);
+ if (state.keyDown(static_cast(key))) {
+ m_sender->handleEventWithText(qstr_str(MP_OBJ_QSTR_VALUE(element.key)), true);
}
}
- Container::activeApp()->dismissModalViewController();
- AppsContainer::sharedAppsContainer()->redrawWindow();
- return true;
}
+ Container::activeApp()->dismissModalViewController();
+ AppsContainer::sharedAppsContainer()->redrawWindow();
+ return true;
+}
- toolboxIonKeys::toolboxIonView::toolboxIonView():
- View()
- {
- }
+ToolboxIonKeys::toolboxIonView::toolboxIonView() :
+ View()
+{
+}
- void toolboxIonKeys::toolboxIonView::drawRect(KDContext * ctx, KDRect rect) const {
- ctx->fillRect(rect, Palette::GrayBright);
- ctx->strokeRect(rect, Palette::GrayDark);
- ctx->drawString(I18n::translate(I18n::Message::PressAKey),KDPoint(rect.left()+80, rect.top()+20));
+void ToolboxIonKeys::toolboxIonView::drawRect(KDContext * ctx, KDRect rect) const {
+ ctx->fillRect(rect, Palette::WallScreen);
+ ctx->strokeRect(rect, Palette::ListCellBorder);
+ KDSize fontSize = KDFont::LargeFont->glyphSize();
+ const char * message = I18n::translate(I18n::Message::PressAKey);
+ // Get the starting position of the text to center it.
+ KDPoint textPosition = KDPoint(rect.size().width() / 2 - strlen(message) * fontSize.width() / 2,
+ rect.size().height() / 2 - fontSize.height() / 2);
- }
+ ctx->drawString(message, textPosition, KDFont::LargeFont, Palette::PrimaryText, Palette::WallScreen);
- View * toolboxIonKeys::view(){
- return &m_view;
- }
+}
+
+View * ToolboxIonKeys::view() {
+ return &m_view;
+}
}
diff --git a/apps/code/toolbox_ion_keys.h b/apps/code/toolbox_ion_keys.h
index 4efe2036d9e..d6706ea3498 100644
--- a/apps/code/toolbox_ion_keys.h
+++ b/apps/code/toolbox_ion_keys.h
@@ -2,9 +2,9 @@
namespace Code {
- class toolboxIonKeys : public ViewController {
+ class ToolboxIonKeys : public ViewController {
public :
- toolboxIonKeys();
+ ToolboxIonKeys();
View * view() override;
bool handleEvent(Ion::Events::Event e) override;
void setSender(InputEventHandler * sender) { m_sender = sender; }
diff --git a/apps/code/variable_box_controller.cpp b/apps/code/variable_box_controller.cpp
index 279c9c57c44..ac39f9986a3 100644
--- a/apps/code/variable_box_controller.cpp
+++ b/apps/code/variable_box_controller.cpp
@@ -128,7 +128,7 @@ void VariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int in
I18n::Message::BuiltinsAndKeywords,
I18n::Message::ImportedModulesAndScripts
};
- static_cast(cell)->setMessage(subtitleMessages[(int)cellOrigin]);
+ static_cast *>(cell)->setMessage(subtitleMessages[(int)cellOrigin]);
}
void VariableBoxController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
@@ -365,7 +365,7 @@ int VariableBoxController::typeAndOriginAtLocation(int i, NodeOrigin * resultOri
}
-bool VariableBoxController::selectLeaf(int rowIndex) {
+bool VariableBoxController::selectLeaf(int rowIndex, bool quitToolbox) {
assert(rowIndex >= 0 && rowIndex < numberOfRows());
m_selectableTableView.deselectTable();
@@ -516,7 +516,7 @@ void VariableBoxController::loadBuiltinNodes(const char * textToAutocomplete, in
assert(sizeof(builtinNames) / sizeof(builtinNames[0]) == k_totalBuiltinNodesCount);
for (int i = 0; i < k_totalBuiltinNodesCount; i++) {
if (addNodeIfMatches(textToAutocomplete, textToAutocompleteLength, builtinNames[i].type, NodeOrigin::Builtins, builtinNames[i].name)) {
- /* We can leverage on the fact that buitin nodes are stored in
+ /* We can leverage on the fact that builtin nodes are stored in
* alphabetical order. */
return;
}
@@ -575,7 +575,7 @@ void VariableBoxController::loadImportedVariablesInScript(const char * scriptCon
}
void VariableBoxController::loadCurrentVariablesInScript(const char * scriptContent, const char * textToAutocomplete, int textToAutocompleteLength) {
- /* To find variable and funtion names: we lex the script and keep all
+ /* To find variable and function names: we lex the script and keep all
* MP_TOKEN_NAME that complete the text to autocomplete and are not already in
* the builtins or imported scripts. */
@@ -653,7 +653,7 @@ void VariableBoxController::loadGlobalAndImportedVariablesInScriptAsImported(Scr
/* At this point, if the script node is not of type "file_input_2", it
* will not have main structures of the wanted type.
* We look for structures at first level (not inside nested scopes) that
- * are either dunction definitions, variables statements or imports. */
+ * are either function definitions, variables statements or imports. */
size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
for (size_t i = 0; i < n; i++) {
mp_parse_node_t child = pns->nodes[i];
@@ -823,18 +823,18 @@ bool VariableBoxController::importationSourceIsModule(const char * sourceName, c
return true;
}
// The sourceName might be a module that is not in the toolbox
- return mp_module_get(qstr_from_str(sourceName)) != MP_OBJ_NULL;
+ return mp_module_get_loaded_or_builtin(qstr_from_str(sourceName)) != MP_OBJ_NULL;
}
-bool VariableBoxController::importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retreivedScript) {
+bool VariableBoxController::importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retrievedScript) {
// Try fetching the nodes from a script
Script importedScript = ScriptStore::ScriptBaseNamed(sourceName);
if (importedScript.isNull()) {
return false;
}
*scriptFullName = importedScript.fullName();
- if (retreivedScript != nullptr) {
- *retreivedScript = importedScript;
+ if (retrievedScript != nullptr) {
+ *retrievedScript = importedScript;
}
return true;
}
diff --git a/apps/code/variable_box_controller.h b/apps/code/variable_box_controller.h
index f8968b41b7f..1a5a525eb45 100644
--- a/apps/code/variable_box_controller.h
+++ b/apps/code/variable_box_controller.h
@@ -43,9 +43,9 @@ class VariableBoxController : public AlternateEmptyNestedMenuController {
private:
constexpr static size_t k_maxNumberOfDisplayedItems = (Ion::Display::Height - Metric::TitleBarHeight - Metric::PopUpTopMargin) / ScriptNodeCell::k_simpleItemHeight + 2; // +2 if the cells are cropped on top and at the bottom
- constexpr static size_t k_maxScriptNodesCount = 32; // Chosen without particular reasons
+ constexpr static size_t k_maxScriptNodesCount = 64; // Chosen without particular reasons (Number of functions in the variables box)
constexpr static int k_totalBuiltinNodesCount = 107;
- constexpr static uint8_t k_scriptOriginsCount = 3;
+ constexpr static uint8_t k_scriptOriginsCount = 8; // Number of scripts loaded in the variable box
constexpr static uint8_t k_subtitleCellType = NodeCellType; // We don't care as it is not selectable
constexpr static uint8_t k_itemCellType = LeafCellType; // So that upper class NestedMenuController knows it's a leaf
constexpr static KDCoordinate k_subtitleRowHeight = 23;
@@ -80,7 +80,7 @@ class VariableBoxController : public AlternateEmptyNestedMenuController {
// NestedMenuController
HighlightCell * leafCellAtIndex(int index) override { assert(false); return nullptr; }
HighlightCell * nodeCellAtIndex(int index) override { assert(false); return nullptr; }
- bool selectLeaf(int rowIndex) override;
+ bool selectLeaf(int rowIndex, bool quitToolbox) override;
void insertTextInCaller(const char * text, int textLength = -1);
// Loading
@@ -92,7 +92,7 @@ class VariableBoxController : public AlternateEmptyNestedMenuController {
bool addNodesFromImportMaybe(mp_parse_node_struct_t * parseNode, const char * textToAutocomplete, int textToAutocompleteLength, bool importFromModules = true);
const char * importationSourceNameFromNode(mp_parse_node_t & node);
bool importationSourceIsModule(const char * sourceName, const ToolboxMessageTree * * moduleChildren = nullptr, int * numberOfModuleChildren = nullptr);
- bool importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retreivedScript = nullptr);
+ bool importationSourceIsScript(const char * sourceName, const char * * scriptFullName, Script * retrievedScript = nullptr);
bool addImportStructFromScript(mp_parse_node_struct_t * pns, uint structKind, const char * scriptName, const char * textToAutocomplete, int textToAutocompleteLength);
/* Add a node if it completes the text to autocomplete and if it is not
* already contained in the variable box. The returned boolean means we
@@ -104,7 +104,7 @@ class VariableBoxController : public AlternateEmptyNestedMenuController {
ScriptNode m_builtinNodes[k_totalBuiltinNodesCount];
ScriptNode m_importedNodes[k_maxScriptNodesCount];
ScriptNodeCell m_itemCells[k_maxNumberOfDisplayedItems];
- MessageTableCell m_subtitleCells[k_scriptOriginsCount];
+ MessageTableCell<> m_subtitleCells[k_scriptOriginsCount];
ScriptStore * m_scriptStore;
size_t m_currentScriptNodesCount;
size_t m_builtinNodesCount;
diff --git a/apps/dummy_timer_manager.cpp b/apps/dummy_timer_manager.cpp
new file mode 100644
index 00000000000..1855d494017
--- /dev/null
+++ b/apps/dummy_timer_manager.cpp
@@ -0,0 +1,6 @@
+#include
+
+// This is the dummy implementation used in tests
+
+void TimerManager::AddTimer(Timer * timer) { }
+void TimerManager::RemoveTimer(Timer * timer) { }
diff --git a/apps/external/app/sample.c b/apps/external/app/sample.c
index dbc13fd9545..a779bf2f42d 100644
--- a/apps/external/app/sample.c
+++ b/apps/external/app/sample.c
@@ -1,6 +1,15 @@
#include
+#if defined _FXCG || defined NSPIRE_NEWLIB
+// On the port, we use the Built-in file manager to import files.
+void host_filemanager();
+void extapp_main() {
+ host_filemanager();
+}
+#else
+// Elsewhere, just draw a rectangle to test the extapp API.
void extapp_main() {
extapp_pushRectUniform(10, 10, LCD_WIDTH-20, LCD_HEIGHT-20, 0);
extapp_msleep(1000);
}
+#endif
diff --git a/apps/external/archive.cpp b/apps/external/archive.cpp
index 8f3d000bf7c..285e262a586 100644
--- a/apps/external/archive.cpp
+++ b/apps/external/archive.cpp
@@ -40,9 +40,10 @@ bool isExamModeAndFileNotExecutable(const TarHeader* tar) {
}
bool fileAtIndex(size_t index, File &entry) {
- if (index == -1)
+ if (index == -1) {
return false;
-
+ }
+
const TarHeader* tar = reinterpret_cast(0x90200000);
unsigned size = 0;
@@ -74,6 +75,8 @@ bool fileAtIndex(size_t index, File &entry) {
entry.data = reinterpret_cast(tar) + sizeof(TarHeader);
entry.dataLength = size;
entry.isExecutable = (tar->mode[4] & 0x01) == 1;
+ // TODO: Handle the trash
+ entry.readable = true;
return true;
} else {
@@ -111,18 +114,31 @@ uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize) {
return -1;
}
-int indexFromName(const char *name) {
- File entry;
- for (int i = 0; fileAtIndex(i, entry); i++) {
- if (strcmp(name, entry.name) == 0) {
- return i;
- }
+#else
+
+bool fileAtIndex(size_t index, File &entry) {
+ if (index != 0) {
+ return false;
}
- return -1;
+ entry.name = "Built-in";
+ entry.data = NULL;
+ entry.dataLength = 0;
+ entry.isExecutable = true;
+ entry.readable = true;
+ return true;
+}
+
+extern "C" void extapp_main(void);
+
+uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize) {
+ extapp_main();
+ return 0;
}
+#endif
+
size_t numberOfFiles() {
File dummy;
size_t count;
@@ -132,6 +148,18 @@ size_t numberOfFiles() {
return count;
}
+int indexFromName(const char *name) {
+ File entry;
+
+ for (int i = 0; fileAtIndex(i, entry); i++) {
+ if (entry.readable && strcmp(name, entry.name) == 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
bool executableAtIndex(size_t index, File &entry) {
File dummy;
size_t count;
@@ -144,16 +172,19 @@ bool executableAtIndex(size_t index, File &entry) {
entry.data = dummy.data;
entry.dataLength = dummy.dataLength;
entry.isExecutable = dummy.isExecutable;
+ entry.readable = dummy.readable;
return true;
}
final_count++;
}
}
-
return false;
}
size_t numberOfExecutables() {
+ if (!GlobalPreferences::sharedGlobalPreferences()->externalAppShown()) {
+ return false;
+ }
File dummy;
size_t count;
size_t final_count = 0;
@@ -165,48 +196,5 @@ size_t numberOfExecutables() {
return final_count;
}
-
-
-#else
-
-bool fileAtIndex(size_t index, File &entry) {
- if (index != 0)
- return false;
-
- entry.name = "Built-in";
- entry.data = NULL;
- entry.dataLength = 0;
- entry.isExecutable = true;
- return true;
-}
-
-bool executableAtIndex(size_t index, File &entry) {
- return fileAtIndex(index, entry);
-}
-
-size_t numberOfExecutables() {
- return 1;
-}
-
-extern "C" void extapp_main(void);
-
-uint32_t executeFile(const char *name, void * heap, const uint32_t heapSize) {
- extapp_main();
- return 0;
-}
-
-int indexFromName(const char *name) {
- if (strcmp(name, "Built-in") == 0)
- return 0;
- else
- return -1;
-}
-
-size_t numberOfFiles() {
- return 1;
-}
-
-#endif
-
}
}
diff --git a/apps/external/archive.h b/apps/external/archive.h
index 670bd138f42..de96e6d204f 100644
--- a/apps/external/archive.h
+++ b/apps/external/archive.h
@@ -14,6 +14,7 @@ struct File {
const uint8_t *data;
size_t dataLength;
bool isExecutable;
+ bool readable;
};
bool fileAtIndex(size_t index, File &entry);
diff --git a/apps/external/base.it.i18n b/apps/external/base.it.i18n
index 49b8a217333..d1341ea6708 100644
--- a/apps/external/base.it.i18n
+++ b/apps/external/base.it.i18n
@@ -1,9 +1,9 @@
-ExternalApp = "External"
-ExternalAppCapital = "EXTERNAL"
-ExternalAppApiMismatch = "API mismatch"
-ExternalAppExecError = "Cannot execute file"
-ExternalNotCompatible = "External is not compatible"
-WithSimulator = "with the simulator"
-WithN0100 = "with n0100"
-GetMoreAppsAt = "Get more apps at"
-NoAppsInstalled = "No apps installed"
+ExternalApp = "Esterna"
+ExternalAppCapital = "ESTERNA"
+ExternalAppApiMismatch = "Discordanza di API"
+ExternalAppExecError = "Impossibile eseguire file"
+ExternalNotCompatible = "Esterna non compatibile"
+WithSimulator = "con il simulatore"
+WithN0100 = "con n0100"
+GetMoreAppsAt = "Ottieni altre app a"
+NoAppsInstalled = "Nessuna app installata"
diff --git a/apps/external/extapp_api.cpp b/apps/external/extapp_api.cpp
index eefd19f5810..23254ab9146 100644
--- a/apps/external/extapp_api.cpp
+++ b/apps/external/extapp_api.cpp
@@ -9,10 +9,16 @@
#include "../apps_container.h"
#include "../global_preferences.h"
+#ifdef DEVICE
+#include
+#include
+#include
+#endif
+
#include
extern "C" {
- #include
+#include
}
uint64_t extapp_millis() {
@@ -30,22 +36,34 @@ uint64_t extapp_scanKeyboard() {
void extapp_pushRect(int16_t x, int16_t y, uint16_t w, uint16_t h, const uint16_t * pixels) {
KDRect rect(x, y, w, h);
- Ion::Display::pushRect(rect, reinterpret_cast(pixels));
+ Ion::Display::pushRect(rect, reinterpret_cast(pixels));
+ #ifndef DEVICE
+ // Refresh the display.
+ Ion::Keyboard::scan();
+ #endif
}
void extapp_pushRectUniform(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t color) {
KDRect rect(x, y, w, h);
Ion::Display::pushRectUniform(rect, KDColor::RGB16(color));
+ #ifndef DEVICE
+ // Refresh the display.
+ Ion::Keyboard::scan();
+ #endif
}
void extapp_pullRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t * pixels) {
KDRect rect(x, y, w, h);
- Ion::Display::pullRect(rect, (KDColor *) pixels);
+ Ion::Display::pullRect(rect, (KDColor *)pixels);
+ #ifndef DEVICE
+ // Refresh the display.
+ Ion::Keyboard::scan();
+ #endif
}
-int16_t extapp_drawTextLarge(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg, bool fake) {
+int16_t extapp_drawTextLarge(const char * text, int16_t x, int16_t y, uint16_t fg, uint16_t bg, bool fake) {
KDPoint point(x, y);
auto ctx = KDIonContext::sharedContext();
@@ -53,10 +71,15 @@ int16_t extapp_drawTextLarge(const char *text, int16_t x, int16_t y, uint16_t fg
ctx->setOrigin(KDPoint(0, 0));
point = ctx->drawString(text, point, KDFont::LargeFont, KDColor::RGB16(fg), KDColor::RGB16(bg));
+ #ifndef DEVICE
+ // Refresh the display.
+ Ion::Keyboard::scan();
+ #endif
+
return point.x();
}
-int16_t extapp_drawTextSmall(const char *text, int16_t x, int16_t y, uint16_t fg, uint16_t bg, bool fake) {
+int16_t extapp_drawTextSmall(const char * text, int16_t x, int16_t y, uint16_t fg, uint16_t bg, bool fake) {
KDPoint point(x, y);
auto ctx = KDIonContext::sharedContext();
@@ -64,6 +87,11 @@ int16_t extapp_drawTextSmall(const char *text, int16_t x, int16_t y, uint16_t fg
ctx->setOrigin(KDPoint(0, 0));
point = ctx->drawString(text, point, KDFont::SmallFont, KDColor::RGB16(fg), KDColor::RGB16(bg));
+ #ifndef DEVICE
+ // Refresh the display.
+ Ion::Keyboard::scan();
+ #endif
+
return point.x();
}
@@ -71,7 +99,7 @@ bool extapp_waitForVBlank() {
return Ion::Display::waitForVBlank();
}
-void extapp_clipboardStore(const char *text) {
+void extapp_clipboardStore(const char * text) {
Clipboard::sharedClipboard()->store(text);
}
@@ -79,101 +107,103 @@ const char * extapp_clipboardText() {
return Clipboard::sharedClipboard()->storedText();
}
+bool match(const char * filename, const char * extension) {
+ return strcmp(filename + strlen(filename) - strlen(extension), extension) == 0;
+}
+
int extapp_fileListWithExtension(const char ** filenames, int maxrecords, const char * extension, int storage) {
- if(storage == EXTAPP_RAM_FILE_SYSTEM) {
+ int j = 0;
+ if (storage == EXTAPP_RAM_FILE_SYSTEM || storage == EXTAPP_BOTH_FILE_SYSTEM) {
int n = Ion::Storage::sharedStorage()->numberOfRecordsWithExtension(extension);
if (n > maxrecords) {
n = maxrecords;
}
- for(int i = 0; i < n; i++) {
- filenames[i] = Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(extension, i).fullName();
+ for (; j < n; j++) {
+ filenames[j] = Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(extension, j).fullName();
}
- return n;
- } else if(storage == EXTAPP_FLASH_FILE_SYSTEM) {
- // TODO: filter by extension
- int n = External::Archive::numberOfFiles();
- if (n > maxrecords) {
- n = maxrecords;
+ if (j == maxrecords) {
+ return j;
}
- for(int i = 0; i < n; i++) {
+ }
+ // Don't read external files the exam mode is enabled
+ if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) return j;
+ if (storage == EXTAPP_FLASH_FILE_SYSTEM || storage == EXTAPP_BOTH_FILE_SYSTEM) {
+ int n = External::Archive::numberOfFiles();
+ for (int i = 0; i < n && j < maxrecords; i++) {
External::Archive::File entry;
- External::Archive::fileAtIndex(i, entry);
- filenames[i] = entry.name;
+ // Filter extension
+ if (External::Archive::fileAtIndex(i, entry) && match(entry.name, extension)) {
+ filenames[j] = entry.name;
+ ++j;
+ }
}
- return n;
- } else {
- return 0;
}
+ return j;
}
bool extapp_fileExists(const char * filename, int storage) {
- if(storage == EXTAPP_RAM_FILE_SYSTEM) {
- return !Ion::Storage::sharedStorage()->recordNamed(filename).isNull();
- } else if(storage == EXTAPP_FLASH_FILE_SYSTEM) {
+ if (storage == EXTAPP_RAM_FILE_SYSTEM || storage == EXTAPP_BOTH_FILE_SYSTEM) {
+ if (!Ion::Storage::sharedStorage()->recordNamed(filename).isNull())
+ return true;
+ }
+ if (storage == EXTAPP_FLASH_FILE_SYSTEM || storage == EXTAPP_BOTH_FILE_SYSTEM) {
return External::Archive::indexFromName(filename) >= 0;
- } else {
- return false;
}
+ return false;
}
bool extapp_fileErase(const char * filename, int storage) {
- if(storage == EXTAPP_RAM_FILE_SYSTEM) {
+ if (storage == EXTAPP_RAM_FILE_SYSTEM) {
Ion::Storage::Record record = Ion::Storage::sharedStorage()->recordNamed(filename);
- if(record.isNull()) {
+ if (record.isNull()) {
return false;
- } else {
- record.destroy();
- return true;
}
- } else {
- return false;
+ record.destroy();
+ return true;
}
+ return false;
}
-const char * extapp_fileRead(const char * filename, size_t *len, int storage) {
- if(storage == EXTAPP_RAM_FILE_SYSTEM) {
+const char * extapp_fileRead(const char * filename, size_t * len, int storage) {
+ if (storage == EXTAPP_RAM_FILE_SYSTEM || storage == EXTAPP_BOTH_FILE_SYSTEM) {
const Ion::Storage::Record record = Ion::Storage::sharedStorage()->recordNamed(filename);
- if (record.isNull()) {
- return NULL;
- } else {
- if(len) {
- *len = record.value().size;
- }
- return (const char *) record.value().buffer;
+ if (!record.isNull()){
+ int delta = 0;
+ if (match(filename, ".py") || match(filename, ".xw"))
+ delta++;
+ // skip record type
+ if (len)
+ *len = record.value().size - delta;
+ return (const char *)record.value().buffer + delta;
}
- } else if(storage == EXTAPP_FLASH_FILE_SYSTEM) {
+ }
+ if (storage == EXTAPP_FLASH_FILE_SYSTEM || storage == EXTAPP_BOTH_FILE_SYSTEM) {
int index = External::Archive::indexFromName(filename);
if (index >= 0) {
External::Archive::File entry;
External::Archive::fileAtIndex(index, entry);
- if(len) {
+ if (len) {
*len = entry.dataLength;
}
return (const char *)entry.data;
- } else {
- return NULL;
}
- } else {
- return NULL;
}
+ return NULL;
}
bool extapp_fileWrite(const char * filename, const char * content, size_t len, int storage) {
- if(storage == EXTAPP_RAM_FILE_SYSTEM) {
+ if (storage == EXTAPP_RAM_FILE_SYSTEM) {
Ion::Storage::Record::ErrorStatus status = Ion::Storage::sharedStorage()->createRecordWithFullName(filename, content, len);
if (status == Ion::Storage::Record::ErrorStatus::NameTaken) {
Ion::Storage::Record::Data data;
data.buffer = content;
data.size = len;
return Ion::Storage::sharedStorage()->recordNamed(filename).setValue(data) == Ion::Storage::Record::ErrorStatus::None;
- } else if (status == Ion::Storage::Record::ErrorStatus::None) {
- return true;
- } else {
- return false;
}
- } else {
- return false;
+ if (status == Ion::Storage::Record::ErrorStatus::None)
+ return true;
}
+ return false;
}
static void reloadTitleBar() {
@@ -244,19 +274,42 @@ const int16_t translated_keys[] =
#define TICKS_PER_MINUTE 11862
#endif
-int extapp_getKey(bool allowSuspend, bool *alphaWasActive) {
+
+int extapp_restoreBackup(int mode) {
+ // Restoring the backup is allowed even if the write protection is enabled, because it may have been writted by Khi.x
+ if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode())
+ return 0;
+ size_t length = 32 * 1024;
+ if (mode == -1) { // restore backup saved when exam mode was set
+ uint8_t * src = (uint8_t *)(0x90800000 - 2 * length);
+ if (src[0] == 0xba && src[1] == 0xdd && src[2] == 0x0b && src[3] == 0xee) {
+ memcpy((uint8_t *)Ion::storageAddress(), src, length);
+ return 1;
+ }
+ }
+ if (mode >= 0 && mode < 16) {
+ uint8_t * src = (uint8_t *)(0x90180000 + mode * length);
+ if (src[0] == 0xba && src[1] == 0xdd && src[2] == 0x0b && src[3] == 0xee) {
+ memcpy((uint8_t *)Ion::storageAddress(), src, length);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int extapp_getKey(int allowSuspend, bool * alphaWasActive) {
int key = -1;
size_t t1 = Ion::Timing::millis();
for (;;) {
int timeout = 10000;
- if(alphaWasActive) {
+ if (alphaWasActive) {
*alphaWasActive = Ion::Events::isAlphaActive();
}
Ion::Events::Event event = Ion::Events::getEvent(&timeout);
reloadTitleBar();
if (event == Ion::Events::None) {
size_t t2 = Ion::Timing::millis();
- if (t2 - t1 > 2 * TICKS_PER_MINUTE) {
+ if (t2 - t1 > 3 * TICKS_PER_MINUTE) {
event = Ion::Events::OnOff;
}
} else {
@@ -270,10 +323,10 @@ int extapp_getKey(bool allowSuspend, bool *alphaWasActive) {
}
if (event.isKeyboardEvent()) {
key = static_cast(event);
- if (key == 17 || key == 4 || key == 5 || key == 52) {
+ if (key == (int)Ion::Keyboard::Key::Backspace || key == (int)Ion::Keyboard::Key::OK || key == (int)Ion::Keyboard::Key::Back || key == (int)Ion::Keyboard::Key::EXE) {
extapp_resetKeyboard();
}
- if (allowSuspend && (key == 7 || key == 8)) { // power
+ if (allowSuspend && key == (int)Ion::Keyboard::Key::OnOff) {
Ion::Power::suspend(true);
extapp_pushRectUniform(0, 0, 320, 240, 65535);
Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel());
@@ -285,6 +338,45 @@ int extapp_getKey(bool allowSuspend, bool *alphaWasActive) {
return translated_keys[key];
}
+bool extapp_isKeydown(int key) {
+ Ion::Keyboard::State scan = Ion::Keyboard::scan();
+ return scan.keyDown(Ion::Keyboard::Key(key));
+}
+
+bool extapp_eraseSector(void * ptr) {
+#ifdef DEVICE
+ if (ptr == 0)
+ Ion::Device::Reset::core();
+ // Disable flash writting
+ if (GlobalPreferences::sharedGlobalPreferences()->externalAppWritePermission()) {
+ int i = Ion::Device::Flash::SectorAtAddress((size_t)ptr);
+ if (i < 0)
+ return false;
+ Ion::Device::Flash::EraseSector(i);
+ return true;
+ }
+#endif
+ return false;
+}
+
+bool extapp_writeMemory(unsigned char * dest, const unsigned char * data, size_t length) {
+#ifdef DEVICE
+ // Disable flash writting
+ if (GlobalPreferences::sharedGlobalPreferences()->externalAppWritePermission()) {
+ int n = Ion::Device::Flash::SectorAtAddress((uint32_t)dest);
+ if (n < 0)
+ return false;
+ Ion::Device::Flash::WriteMemory(dest, (unsigned char *)data, length);
+ return true;
+ }
+#endif
+ return false;
+}
+
+bool extapp_inExamMode() {
+ return GlobalPreferences::sharedGlobalPreferences()->isInExamMode();
+}
+
extern "C" void (* const apiPointers[])(void) = {
(void (*)(void)) extapp_millis,
(void (*)(void)) extapp_msleep,
@@ -305,5 +397,10 @@ extern "C" void (* const apiPointers[])(void) = {
(void (*)(void)) extapp_lockAlpha,
(void (*)(void)) extapp_resetKeyboard,
(void (*)(void)) extapp_getKey,
+ (void (*)(void)) extapp_isKeydown,
+ (void (*)(void)) extapp_restoreBackup,
+ (void (*)(void)) extapp_eraseSector,
+ (void (*)(void)) extapp_writeMemory,
+ (void (*)(void)) extapp_inExamMode,
(void (*)(void)) nullptr,
-};
+};
\ No newline at end of file
diff --git a/apps/external/extapp_api.h b/apps/external/extapp_api.h
index b17b8643673..9a98e5526d4 100644
--- a/apps/external/extapp_api.h
+++ b/apps/external/extapp_api.h
@@ -18,6 +18,7 @@
#define EXTAPP_RAM_FILE_SYSTEM 0
#define EXTAPP_FLASH_FILE_SYSTEM 1
+#define EXTAPP_BOTH_FILE_SYSTEM 2
#define SCANCODE_Left ((uint64_t)1 << 0)
#define SCANCODE_Up ((uint64_t)1 << 1)
@@ -251,6 +252,10 @@ EXTERNC const char * extapp_fileRead(const char * filename, size_t *len, int sto
EXTERNC bool extapp_fileWrite(const char * filename, const char * content, size_t len, int storage);
EXTERNC void extapp_lockAlpha();
EXTERNC void extapp_resetKeyboard();
-EXTERNC int extapp_getKey(bool allowSuspend, bool *alphaWasActive);
+EXTERNC int extapp_getKey(int allowSuspend, bool *alphaWasActive);
+EXTERNC bool extapp_isKeydown(int key);
+EXTERNC int extapp_restoreBackup(int mode); // Keep for compatibility with KhiCAS on Khi
+EXTERNC bool extapp_eraseSector(void * ptr);
+EXTERNC bool extapp_writeMemory(unsigned char * dest,const unsigned char * data,size_t length);
#endif
diff --git a/apps/global_preferences.cpp b/apps/global_preferences.cpp
index 938cff8616a..c0eac31c866 100644
--- a/apps/global_preferences.cpp
+++ b/apps/global_preferences.cpp
@@ -41,6 +41,25 @@ void GlobalPreferences::setBrightnessLevel(int brightnessLevel) {
brightnessLevel = brightnessLevel < 0 ? 0 : brightnessLevel;
brightnessLevel = brightnessLevel > Ion::Backlight::MaxBrightness ? Ion::Backlight::MaxBrightness : brightnessLevel;
m_brightnessLevel = brightnessLevel;
- Ion::Backlight::setBrightness(m_brightnessLevel);
}
}
+
+void GlobalPreferences::setIdleBeforeSuspendSeconds(int idleBeforeSuspendSeconds) {
+ if (m_idleBeforeSuspendSeconds != idleBeforeSuspendSeconds) {
+ idleBeforeSuspendSeconds = idleBeforeSuspendSeconds < 5 ? 5 : idleBeforeSuspendSeconds;
+ idleBeforeSuspendSeconds = idleBeforeSuspendSeconds > 7200 ? 7200 : idleBeforeSuspendSeconds;
+ m_idleBeforeSuspendSeconds = idleBeforeSuspendSeconds;
+ }
+}
+
+void GlobalPreferences::setIdleBeforeDimmingSeconds(int idleBeforeDimmingSeconds) {
+ if (m_idleBeforeDimmingSeconds != idleBeforeDimmingSeconds) {
+ idleBeforeDimmingSeconds = idleBeforeDimmingSeconds < 3 ? 3 : idleBeforeDimmingSeconds;
+ idleBeforeDimmingSeconds = idleBeforeDimmingSeconds > 1200 ? 1200 : idleBeforeDimmingSeconds;
+ m_idleBeforeDimmingSeconds = idleBeforeDimmingSeconds;
+ }
+}
+
+void GlobalPreferences::setBrightnessShortcut(int brightnessShortcut){
+ m_brightnessShortcut = brightnessShortcut;
+}
diff --git a/apps/global_preferences.h b/apps/global_preferences.h
index 4367c20f788..3077b93fee2 100644
--- a/apps/global_preferences.h
+++ b/apps/global_preferences.h
@@ -30,11 +30,27 @@ class GlobalPreferences {
void setTempExamMode(ExamMode examMode);
bool showPopUp() const { return m_showPopUp; }
void setShowPopUp(bool showPopUp) { m_showPopUp = showPopUp; }
+ bool dfuUnlocked() const { return m_dfuUnlocked; }
+ void setDfuUnlocked(bool unlocked) { m_dfuUnlocked = unlocked; }
+ bool autocomplete() const { return m_autoComplete; }
+ void setAutocomplete(bool autocomple) { m_autoComplete = autocomple; }
+ bool syntaxhighlighting() const { return m_syntaxhighlighting; }
+ void setSyntaxhighlighting(bool syntaxhighlight) { m_syntaxhighlighting = syntaxhighlight; }
int brightnessLevel() const { return m_brightnessLevel; }
void setBrightnessLevel(int brightnessLevel);
const KDFont * font() const { return m_font; }
void setFont(const KDFont * font) { m_font = font; }
constexpr static int NumberOfBrightnessStates = 15;
+ int idleBeforeSuspendSeconds() const { return m_idleBeforeSuspendSeconds; }
+ void setIdleBeforeSuspendSeconds(int m_idleBeforeSuspendSeconds);
+ int idleBeforeDimmingSeconds() const { return m_idleBeforeDimmingSeconds; }
+ void setIdleBeforeDimmingSeconds(int m_idleBeforeDimmingSeconds);
+ int brightnessShortcut() const { return m_brightnessShortcut; }
+ void setBrightnessShortcut(int m_BrightnessShortcut);
+ bool externalAppWritePermission() const { return m_externalAppWritePermission; }
+ void setExternalAppWritePermission(bool extapp_write) { m_externalAppWritePermission = extapp_write; }
+ bool externalAppShown() const { return m_externalAppShown; }
+ void setExternalAppShown(bool externalAppShown) { m_externalAppShown = externalAppShown; }
private:
static_assert(I18n::NumberOfLanguages > 0, "I18n::NumberOfLanguages is not superior to 0"); // There should already have been an error when processing an empty EPSILON_I18N flag
static_assert(I18n::NumberOfCountries > 0, "I18n::NumberOfCountries is not superior to 0"); // There should already have been an error when processing an empty EPSILON_COUNTRIES flag
@@ -44,7 +60,15 @@ class GlobalPreferences {
m_examMode(ExamMode::Unknown),
m_tempExamMode(ExamMode::Standard),
m_showPopUp(true),
+ m_dfuUnlocked(false),
+ m_autoComplete(true),
+ m_syntaxhighlighting(true),
m_brightnessLevel(Ion::Backlight::MaxBrightness),
+ m_idleBeforeSuspendSeconds(55),
+ m_idleBeforeDimmingSeconds(45),
+ m_brightnessShortcut(4),
+ m_externalAppWritePermission(false),
+ m_externalAppShown(true),
m_font(KDFont::LargeFont) {}
I18n::Language m_language;
I18n::Country m_country;
@@ -53,7 +77,15 @@ class GlobalPreferences {
mutable ExamMode m_examMode;
mutable ExamMode m_tempExamMode;
bool m_showPopUp;
+ bool m_dfuUnlocked;
+ bool m_autoComplete;
+ bool m_syntaxhighlighting;
int m_brightnessLevel;
+ int m_idleBeforeSuspendSeconds;
+ int m_idleBeforeDimmingSeconds;
+ int m_brightnessShortcut;
+ bool m_externalAppWritePermission;
+ bool m_externalAppShown;
const KDFont * m_font;
};
diff --git a/apps/graph/app.cpp b/apps/graph/app.cpp
index 68a4b4a9e7f..b4a74d8e4fc 100644
--- a/apps/graph/app.cpp
+++ b/apps/graph/app.cpp
@@ -27,7 +27,8 @@ const Image * App::Descriptor::icon() {
App::Snapshot::Snapshot() :
Shared::FunctionApp::Snapshot::Snapshot(),
m_functionStore(),
- m_graphRange()
+ m_graphRange(),
+ m_shouldDisplayDerivative(false)
{
}
@@ -40,6 +41,7 @@ void App::Snapshot::reset() {
for (int i = 0; i < Shared::ContinuousFunction::k_numberOfPlotTypes; i++) {
m_interval[i].reset();
}
+ m_shouldDisplayDerivative = false;
}
App::Descriptor * App::Snapshot::descriptor() {
@@ -58,7 +60,7 @@ App::App(Snapshot * snapshot) :
m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGray),
m_listHeader(&m_listStackViewController, &m_listFooter, &m_listController),
m_listStackViewController(&m_tabViewController, &m_listHeader),
- m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->rangeVersion(), &m_graphHeader),
+ m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->rangeVersion(), &m_graphHeader, snapshot->shouldDisplayDerivative()),
m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController),
m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController),
m_graphStackViewController(&m_tabViewController, &m_graphHeader),
diff --git a/apps/graph/app.h b/apps/graph/app.h
index f9255732908..715c8bd2d7f 100644
--- a/apps/graph/app.h
+++ b/apps/graph/app.h
@@ -31,11 +31,13 @@ class App : public Shared::FunctionApp {
Shared::Interval * intervalForType(Shared::ContinuousFunction::PlotType plotType) {
return m_interval + static_cast(plotType);
}
+ bool * shouldDisplayDerivative() { return &m_shouldDisplayDerivative; }
private:
void tidy() override;
ContinuousFunctionStore m_functionStore;
Shared::InteractiveCurveViewRange m_graphRange;
Shared::Interval m_interval[Shared::ContinuousFunction::k_numberOfPlotTypes];
+ bool m_shouldDisplayDerivative;
};
static App * app() {
return static_cast(Container::activeApp());
diff --git a/apps/graph/graph/calculation_parameter_controller.cpp b/apps/graph/graph/calculation_parameter_controller.cpp
index 93f98086fda..3e726666263 100644
--- a/apps/graph/graph/calculation_parameter_controller.cpp
+++ b/apps/graph/graph/calculation_parameter_controller.cpp
@@ -109,7 +109,7 @@ void CalculationParameterController::willDisplayCellForIndex(HighlightCell * cel
assert(index >= 0 && index <= numberOfRows());
if (cell != &m_preimageCell) {
I18n::Message titles[] = {I18n::Message::Intersection, I18n::Message::Maximum, I18n::Message::Minimum, I18n::Message::Zeros, I18n::Message::Tangent, I18n::Message::Integral};
- static_cast(cell)->setMessage(titles[index - 1 + !shouldDisplayIntersection()]);
+ static_cast *>(cell)->setMessage(titles[index - 1 + !shouldDisplayIntersection()]);
}
}
diff --git a/apps/graph/graph/calculation_parameter_controller.h b/apps/graph/graph/calculation_parameter_controller.h
index ffb38e6919a..0297b5b38c3 100644
--- a/apps/graph/graph/calculation_parameter_controller.h
+++ b/apps/graph/graph/calculation_parameter_controller.h
@@ -32,9 +32,9 @@ class CalculationParameterController : public ViewController, public ListViewDat
void setRecord(Ion::Storage::Record record);
private:
bool shouldDisplayIntersection() const;
- MessageTableCellWithChevron m_preimageCell;
+ MessageTableCellWithChevron<> m_preimageCell;
constexpr static int k_totalNumberOfReusableCells = 6;
- MessageTableCell m_cells[k_totalNumberOfReusableCells];
+ MessageTableCell<> m_cells[k_totalNumberOfReusableCells];
SelectableTableView m_selectableTableView;
Ion::Storage::Record m_record;
PreimageParameterController m_preimageParameterController;
diff --git a/apps/graph/graph/curve_parameter_controller.h b/apps/graph/graph/curve_parameter_controller.h
index d5a587af16d..a14e329564c 100644
--- a/apps/graph/graph/curve_parameter_controller.h
+++ b/apps/graph/graph/curve_parameter_controller.h
@@ -25,7 +25,7 @@ class CurveParameterController : public Shared::FunctionCurveParameterController
Shared::FunctionGoToParameterController * goToParameterController() override;
Shared::FunctionGoToParameterController m_goToParameterController;
GraphController * m_graphController;
- MessageTableCellWithChevron m_calculationCell;
+ MessageTableCellWithChevron<> m_calculationCell;
MessageTableCellWithSwitch m_derivativeCell;
CalculationParameterController m_calculationParameterController;
};
diff --git a/apps/graph/graph/graph_controller.cpp b/apps/graph/graph/graph_controller.cpp
index a6de8426862..a07d49b39c9 100644
--- a/apps/graph/graph/graph_controller.cpp
+++ b/apps/graph/graph/graph_controller.cpp
@@ -7,13 +7,13 @@ using namespace Shared;
namespace Graph {
-GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * rangeVersion, ButtonRowController * header) :
+GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * rangeVersion, ButtonRowController * header, bool * shouldDisplayDerivative) :
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, rangeVersion),
m_bannerView(this, inputEventHandlerDelegate, this),
m_view(curveViewRange, m_cursor, &m_bannerView, &m_cursorView),
m_graphRange(curveViewRange),
m_curveParameterController(inputEventHandlerDelegate, curveViewRange, &m_bannerView, m_cursor, &m_view, this),
- m_displayDerivativeInBanner(false)
+ m_displayDerivativeInBanner(shouldDisplayDerivative)
{
m_graphRange->setDelegate(this);
}
@@ -47,7 +47,7 @@ void GraphController::selectFunctionWithCursor(int functionIndex) {
void GraphController::reloadBannerView() {
Ion::Storage::Record record = functionStore()->activeRecordAtIndex(indexFunctionSelectedByCursor());
- bool displayDerivative = m_displayDerivativeInBanner &&
+ bool displayDerivative = *m_displayDerivativeInBanner &&
functionStore()->modelForRecord(record)->plotType() == ContinuousFunction::PlotType::Cartesian;
m_bannerView.setNumberOfSubviews(Shared::XYBannerView::k_numberOfSubviews + displayDerivative);
FunctionGraphController::reloadBannerView();
diff --git a/apps/graph/graph/graph_controller.h b/apps/graph/graph/graph_controller.h
index 433ab9ebe23..a740f4adcb5 100644
--- a/apps/graph/graph/graph_controller.h
+++ b/apps/graph/graph/graph_controller.h
@@ -15,13 +15,13 @@ namespace Graph {
class GraphController : public Shared::FunctionGraphController, public GraphControllerHelper {
public:
- GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * rangeVersion, ButtonRowController * header);
+ GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * rangeVersion, ButtonRowController * header, bool * shouldDisplayDerivative);
I18n::Message emptyMessage() override;
void viewWillAppear() override;
- bool displayDerivativeInBanner() const { return m_displayDerivativeInBanner; }
- void setDisplayDerivativeInBanner(bool displayDerivative) { m_displayDerivativeInBanner = displayDerivative; }
+ bool displayDerivativeInBanner() const { return *m_displayDerivativeInBanner; }
+ void setDisplayDerivativeInBanner(bool displayDerivative) { *m_displayDerivativeInBanner = displayDerivative; }
private:
- int estimatedBannerNumberOfLines() const override { return 1 + m_displayDerivativeInBanner; }
+ int estimatedBannerNumberOfLines() const override { return 1 + *m_displayDerivativeInBanner; }
void selectFunctionWithCursor(int functionIndex) override;
BannerView * bannerView() override { return &m_bannerView; }
void reloadBannerView() override;
@@ -41,7 +41,7 @@ class GraphController : public Shared::FunctionGraphController, public GraphCont
GraphView m_view;
Shared::InteractiveCurveViewRange * m_graphRange;
CurveParameterController m_curveParameterController;
- bool m_displayDerivativeInBanner;
+ bool * m_displayDerivativeInBanner;
};
}
diff --git a/apps/graph/graph/graph_view.h b/apps/graph/graph/graph_view.h
index ded212f6db3..87688114037 100644
--- a/apps/graph/graph/graph_view.h
+++ b/apps/graph/graph/graph_view.h
@@ -18,7 +18,13 @@ class GraphView : public Shared::FunctionGraphView {
* 10.0938275501223 which are hopefully rare enough.
* TODO: The drawCurve algorithm should use the derivative function to know
* how fast the function moves... */
+ #ifndef _FXCG
static constexpr float k_graphStepDenominator = 10.0938275501223f;
+ #else
+ // This value rounded down has to be a factor of the horizontal resolution / 2
+ // On the Casio calculator the resolution is 396 pixels, so 11 is close but works
+ static constexpr float k_graphStepDenominator = 11.0938275501223f;
+ #endif
GraphView(Shared::InteractiveCurveViewRange * graphRange,
Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, Shared::CursorView * cursorView);
diff --git a/apps/graph/list/list_controller.h b/apps/graph/list/list_controller.h
index 12deaf33bb2..b116f34a172 100644
--- a/apps/graph/list/list_controller.h
+++ b/apps/graph/list/list_controller.h
@@ -21,6 +21,8 @@ class ListController : public Shared::FunctionListController, public Shared::Tex
bool textFieldDidAbortEditing(TextField * textField) override;
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
+protected:
+ virtual const char * recordExtension() const override { return Ion::Storage::funcExtension; }
private:
constexpr static int k_maxNumberOfDisplayableRows = 5;
Shared::ListParameterController * parameterController() override;
diff --git a/apps/graph/list/list_parameter_controller.cpp b/apps/graph/list/list_parameter_controller.cpp
index 29b7bbdef70..01d266db2f2 100644
--- a/apps/graph/list/list_parameter_controller.cpp
+++ b/apps/graph/list/list_parameter_controller.cpp
@@ -41,7 +41,7 @@ bool ListParameterController::handleEvent(Ion::Events::Event event) {
}
if (event == Ion::Events::Right) {
int selectedR = selectedRow();
- if (selectedR == 0 || selectedR == 1) {
+ if (selectedR == 0 || selectedR == 1 || selectedR == 3) {
// Go in the submenu
return handleEnterOnRow(selectedR);
}
diff --git a/apps/graph/list/list_parameter_controller.h b/apps/graph/list/list_parameter_controller.h
index 31c311ba4be..2246ab8666f 100644
--- a/apps/graph/list/list_parameter_controller.h
+++ b/apps/graph/list/list_parameter_controller.h
@@ -28,7 +28,7 @@ class ListParameterController : public Shared::ListParameterController {
MessageTableCellWithChevronAndBuffer m_functionDomain;
TypeParameterController m_typeParameterController;
DomainParameterController m_domainParameterController;
- MessageTableCell m_renameCell;
+ MessageTableCell<> m_renameCell;
};
}
diff --git a/apps/graph/list/text_field_function_title_cell.h b/apps/graph/list/text_field_function_title_cell.h
index 05d6dcab7e7..7dc4d962a39 100644
--- a/apps/graph/list/text_field_function_title_cell.h
+++ b/apps/graph/list/text_field_function_title_cell.h
@@ -11,7 +11,7 @@ class ListController;
class TextFieldFunctionTitleCell : public Shared::FunctionTitleCell, public Responder {
public:
- TextFieldFunctionTitleCell(ListController * listController, Orientation orientation = Orientation::VerticalIndicator, const KDFont * font = KDFont::LargeFont);
+ TextFieldFunctionTitleCell(ListController * listController, Orientation orientation = Orientation::VerticalIndicator, const KDFont * font = KDFont::ItalicLargeFont);
TextField * textField() { return &m_textField; }
void setEditing(bool editing);
bool isEditing() const;
diff --git a/apps/graph/values/derivative_parameter_controller.h b/apps/graph/values/derivative_parameter_controller.h
index 10d64bec0a4..2c353a1d947 100644
--- a/apps/graph/values/derivative_parameter_controller.h
+++ b/apps/graph/values/derivative_parameter_controller.h
@@ -33,9 +33,9 @@ class DerivativeParameterController : public ViewController, public SimpleListVi
#endif
constexpr static int k_maxNumberOfCharsInTitle = Shared::Function::k_maxNameWithArgumentSize + 1; // +1 for the ' of the derivative
char m_pageTitle[k_maxNumberOfCharsInTitle];
- MessageTableCell m_hideColumn;
+ MessageTableCell<> m_hideColumn;
#if COPY_COLUMN
- MessageTableCellWithChevron m_copyColumn;
+ MessageTableCellWithChevron<> m_copyColumn;
#endif
SelectableTableView m_selectableTableView;
Ion::Storage::Record m_record;
diff --git a/apps/graph/values/interval_parameter_selector_controller.cpp b/apps/graph/values/interval_parameter_selector_controller.cpp
index 80cd68f7431..7707c83ed83 100644
--- a/apps/graph/values/interval_parameter_selector_controller.cpp
+++ b/apps/graph/values/interval_parameter_selector_controller.cpp
@@ -69,7 +69,7 @@ int IntervalParameterSelectorController::reusableCellCount() const {
void IntervalParameterSelectorController::willDisplayCellForIndex(HighlightCell * cell, int index) {
assert(0 <= index && index < numberOfRows());
Shared::ContinuousFunction::PlotType plotType = plotTypeAtRow(index);
- static_cast(cell)->setMessage(messageForType(plotType));
+ static_cast *>(cell)->setMessage(messageForType(plotType));
}
Shared::ContinuousFunction::PlotType IntervalParameterSelectorController::plotTypeAtRow(int j) const {
diff --git a/apps/graph/values/interval_parameter_selector_controller.h b/apps/graph/values/interval_parameter_selector_controller.h
index eef6e1b6a99..a37e714ad5d 100644
--- a/apps/graph/values/interval_parameter_selector_controller.h
+++ b/apps/graph/values/interval_parameter_selector_controller.h
@@ -24,7 +24,7 @@ class IntervalParameterSelectorController : public ViewController, public Simple
private:
Shared::ContinuousFunction::PlotType plotTypeAtRow(int j) const;
I18n::Message messageForType(Shared::ContinuousFunction::PlotType plotType);
- MessageTableCellWithChevron m_intervalParameterCell[Shared::ContinuousFunction::k_numberOfPlotTypes];
+ MessageTableCellWithChevron<> m_intervalParameterCell[Shared::ContinuousFunction::k_numberOfPlotTypes];
SelectableTableView m_selectableTableView;
};
diff --git a/apps/graph/values/values_controller.cpp b/apps/graph/values/values_controller.cpp
index d5783efce66..56bebd1c14a 100644
--- a/apps/graph/values/values_controller.cpp
+++ b/apps/graph/values/values_controller.cpp
@@ -343,7 +343,7 @@ EvenOddBufferTextCell * ValuesController::floatCells(int j) {
/* ValuesController::ValuesSelectableTableView */
-int writeMatrixBrakets(char * buffer, const int bufferSize, int type) {
+int writeMatrixBrackets(char * buffer, const int bufferSize, int type) {
/* Write the double brackets required in matrix notation.
* - type == 1: "[["
* - type == 0: "]["
@@ -365,14 +365,14 @@ bool ValuesController::ValuesSelectableTableView::handleEvent(Ion::Events::Event
constexpr int bufferSize = 2*PrintFloat::k_maxFloatCharSize + 6; // "[[a][b]]" gives 6 characters in addition to the 2 floats
char buffer[bufferSize];
int currentChar = 0;
- currentChar += writeMatrixBrakets(buffer + currentChar, bufferSize - currentChar, -1);
+ currentChar += writeMatrixBrackets(buffer + currentChar, bufferSize - currentChar, -1);
assert(currentChar < bufferSize-1);
size_t semiColonPosition = UTF8Helper::CopyUntilCodePoint(buffer+currentChar, TextField::maxBufferSize() - currentChar, text+1, ';');
currentChar += semiColonPosition;
- currentChar += writeMatrixBrakets(buffer + currentChar, bufferSize - currentChar, 0);
+ currentChar += writeMatrixBrackets(buffer + currentChar, bufferSize - currentChar, 0);
assert(currentChar < bufferSize-1);
currentChar += UTF8Helper::CopyUntilCodePoint(buffer+currentChar, TextField::maxBufferSize() - currentChar, text+1+semiColonPosition+1, ')');
- currentChar += writeMatrixBrakets(buffer + currentChar, bufferSize - currentChar, 1);
+ currentChar += writeMatrixBrackets(buffer + currentChar, bufferSize - currentChar, 1);
assert(currentChar < bufferSize-1);
buffer[currentChar] = 0;
Clipboard::sharedClipboard()->store(buffer);
diff --git a/apps/home/Makefile b/apps/home/Makefile
index 880302a5262..d23bcdc30f2 100644
--- a/apps/home/Makefile
+++ b/apps/home/Makefile
@@ -12,7 +12,7 @@ i18n_files += $(call i18n_without_universal_for,home/base)
# Apps layout file generation
-# The header is refered to as so make sure it's
+# The header is referred to as so make sure it's
# findable this way
SFLAGS += -I$(BUILD_DIR)
diff --git a/apps/home/apps_layout.csv b/apps/home/apps_layout.csv
index 77e47e4b882..423aa17ce23 100644
--- a/apps/home/apps_layout.csv
+++ b/apps/home/apps_layout.csv
@@ -1,2 +1,2 @@
-Default,calculation,rpn,graph,code,statistics,probability,solver,atomic,sequence,regression,settings
-HidePython,calculation,rpn,graph,code,statistics,probability,solver,atomic,sequence,regression,settings
+Default,calculation,graph,rpn,code,statistics,probability,solver,atomic,sequence,regression,reader,settings
+HidePython,calculation,graph,rpn,code,statistics,probability,solver,atomic,sequence,regression,reader,settings
diff --git a/apps/home/base.de.i18n b/apps/home/base.de.i18n
index 30ac1c9c256..e360771484b 100644
--- a/apps/home/base.de.i18n
+++ b/apps/home/base.de.i18n
@@ -1,4 +1,4 @@
Apps = "Anwendungen"
-AppsCapital = "OMEGA"
-ForbidenAppInExamMode1 = "Diese Anwendung ist im"
-ForbidenAppInExamMode2 = "Prüfungsmodus nicht erlaubt."
+AppsCapital = "UPSILON"
+ForbiddenAppInExamMode1 = "Diese Anwendung ist im"
+ForbiddenAppInExamMode2 = "Prüfungsmodus nicht erlaubt."
diff --git a/apps/home/base.en.i18n b/apps/home/base.en.i18n
index dde4e21299b..2a65458e814 100644
--- a/apps/home/base.en.i18n
+++ b/apps/home/base.en.i18n
@@ -1,4 +1,4 @@
Apps = "Applications"
-AppsCapital = "OMEGA"
-ForbidenAppInExamMode1 = "This application is"
-ForbidenAppInExamMode2 = "forbidden in exam mode"
+AppsCapital = "UPSILON"
+ForbiddenAppInExamMode1 = "This application is"
+ForbiddenAppInExamMode2 = "forbidden in exam mode"
diff --git a/apps/home/base.es.i18n b/apps/home/base.es.i18n
index 93e7bdf4914..8d71a322920 100644
--- a/apps/home/base.es.i18n
+++ b/apps/home/base.es.i18n
@@ -1,4 +1,4 @@
Apps = "Aplicaciones"
-AppsCapital = "OMEGA"
-ForbidenAppInExamMode1 = "Esta aplicación está prohibida"
-ForbidenAppInExamMode2 = "en el modo de examen"
+AppsCapital = "UPSILON"
+ForbiddenAppInExamMode1 = "Esta aplicación está prohibida"
+ForbiddenAppInExamMode2 = "en el modo de examen"
diff --git a/apps/home/base.fr.i18n b/apps/home/base.fr.i18n
index 8280b458409..8c7270e051c 100644
--- a/apps/home/base.fr.i18n
+++ b/apps/home/base.fr.i18n
@@ -1,4 +1,4 @@
Apps = "Applications"
-AppsCapital = "OMEGA"
-ForbidenAppInExamMode1 = "Cette application n'est"
-ForbidenAppInExamMode2 = "pas autorisée en mode examen."
+AppsCapital = "UPSILON"
+ForbiddenAppInExamMode1 = "Cette application n'est"
+ForbiddenAppInExamMode2 = "pas autorisée en mode examen."
diff --git a/apps/home/base.hu.i18n b/apps/home/base.hu.i18n
index 6b0b188157c..aa3c0f1e3b7 100644
--- a/apps/home/base.hu.i18n
+++ b/apps/home/base.hu.i18n
@@ -1,4 +1,4 @@
Apps = "Alkalmazások"
-AppsCapital = "OMEGA"
-ForbidenAppInExamMode1 = "Ez az alkalmazás"
-ForbidenAppInExamMode2 = "tilos vizsga módban"
+AppsCapital = "UPSILON"
+ForbiddenAppInExamMode1 = "Ez az alkalmazás"
+ForbiddenAppInExamMode2 = "tilos vizsga módban"
diff --git a/apps/home/base.it.i18n b/apps/home/base.it.i18n
index 95373c0401a..a4bf010540b 100644
--- a/apps/home/base.it.i18n
+++ b/apps/home/base.it.i18n
@@ -1,4 +1,4 @@
Apps = "Applicazioni"
-AppsCapital = "OMEGA"
-ForbidenAppInExamMode1 = "Questa applicazione è"
-ForbidenAppInExamMode2 = "proibita nella modalità d'esame"
+AppsCapital = "UPSILON"
+ForbiddenAppInExamMode1 = "Questa applicazione è"
+ForbiddenAppInExamMode2 = "proibita nella modalità d'esame"
diff --git a/apps/home/base.nl.i18n b/apps/home/base.nl.i18n
index dd6a8991935..4e9b4470eff 100644
--- a/apps/home/base.nl.i18n
+++ b/apps/home/base.nl.i18n
@@ -1,4 +1,4 @@
Apps = "Applicaties"
-AppsCapital = "OMEGA"
-ForbidenAppInExamMode1 = "Deze applicatie is"
-ForbidenAppInExamMode2 = "uitgesloten in examenstand"
+AppsCapital = "UPSILON"
+ForbiddenAppInExamMode1 = "Deze applicatie is"
+ForbiddenAppInExamMode2 = "uitgesloten in examenstand"
diff --git a/apps/home/base.pt.i18n b/apps/home/base.pt.i18n
index f3efc8ffdee..7f5c4d004e7 100644
--- a/apps/home/base.pt.i18n
+++ b/apps/home/base.pt.i18n
@@ -1,4 +1,4 @@
Apps = "Aplicações"
-AppsCapital = "OMEGA"
-ForbidenAppInExamMode1 = "Esta aplicação é"
-ForbidenAppInExamMode2 = "proibida no Modo de Exame"
+AppsCapital = "UPSILON"
+ForbiddenAppInExamMode1 = "Esta aplicação é"
+ForbiddenAppInExamMode2 = "proibida no Modo de Exame"
diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp
index df725f10fdc..1936b47eff7 100644
--- a/apps/home/controller.cpp
+++ b/apps/home/controller.cpp
@@ -75,7 +75,7 @@ Controller::Controller(Responder * parentResponder, SelectableTableViewDataSourc
m_view.backgroundView()->setDefaultColor(Palette::HomeBackground);
-
+
#ifdef HOME_DISPLAY_EXTERNALS
int index = External::Archive::indexFromName("wallpaper.obm");
if(index > -1) {
@@ -86,6 +86,13 @@ Controller::Controller(Responder * parentResponder, SelectableTableViewDataSourc
#endif
}
+static constexpr Ion::Events::Event home_fast_navigation_events[] = {
+ Ion::Events::Seven, Ion::Events::Eight, Ion::Events::Nine,
+ Ion::Events::Four, Ion::Events::Five, Ion::Events::Six,
+ Ion::Events::One, Ion::Events::Two, Ion::Events::Three,
+ Ion::Events::Zero, Ion::Events::Dot, Ion::Events::EE
+};
+
bool Controller::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
AppsContainer * container = AppsContainer::sharedAppsContainer();
@@ -94,7 +101,7 @@ bool Controller::handleEvent(Ion::Events::Event event) {
#ifdef HOME_DISPLAY_EXTERNALS
if (index >= container->numberOfApps()) {
if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Dutch || GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::NoSymNoText || GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::NoSym) {
- App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2);
+ App::app()->displayWarning(I18n::Message::ForbiddenAppInExamMode1, I18n::Message::ForbiddenAppInExamMode2);
} else {
External::Archive::File executable;
if (External::Archive::executableAtIndex(index - container->numberOfApps(), executable)) {
@@ -120,7 +127,7 @@ bool Controller::handleEvent(Ion::Events::Event event) {
#endif
::App::Snapshot * selectedSnapshot = container->appSnapshotAtIndex(index);
if (ExamModeConfiguration::appIsForbiddenInExamMode(selectedSnapshot->descriptor()->examinationLevel(), GlobalPreferences::sharedGlobalPreferences()->examMode())) {
- App::app()->displayWarning(I18n::Message::ForbidenAppInExamMode1, I18n::Message::ForbidenAppInExamMode2);
+ App::app()->displayWarning(I18n::Message::ForbiddenAppInExamMode1, I18n::Message::ForbiddenAppInExamMode2);
} else {
bool switched = container->switchTo(selectedSnapshot);
assert(switched);
@@ -143,6 +150,21 @@ bool Controller::handleEvent(Ion::Events::Event event) {
return m_view.selectableTableView()->selectCellAtLocation(numberOfColumns() - 1, selectionDataSource()->selectedRow() - 1);
}
+ // Handle fast home navigation
+ for(int i = 0; i < std::min((int) (sizeof(home_fast_navigation_events) / sizeof(Ion::Events::Event)), this->numberOfIcons()); i++) {
+ if (event == home_fast_navigation_events[i]) {
+ int row = i / k_numberOfColumns;
+ int column = i % k_numberOfColumns;
+ // Get if app is already selected
+ if (selectionDataSource()->selectedRow() == row && selectionDataSource()->selectedColumn() == column) {
+ // If app is already selected, launch it
+ return handleEvent(Ion::Events::OK);
+ }
+ // Else, select the app
+ return m_view.selectableTableView()->selectCellAtLocation(column, row);
+ }
+ }
+
return false;
}
@@ -254,7 +276,7 @@ void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previo
* (so the previous one is always visible). */
int appIndex = (t->selectedColumn()+t->selectedRow()*k_numberOfColumns)+1;
if (appIndex >= this->numberOfIcons()+1) {
- t->selectCellAtLocation((this->numberOfIcons()%3)-1, (this->numberOfIcons() / k_numberOfColumns));
+ t->selectCellAtLocation((this->numberOfIcons()%k_numberOfColumns)-1, (this->numberOfIcons() / k_numberOfColumns));
}
}
diff --git a/apps/home/controller.h b/apps/home/controller.h
index 3301fac78fb..a330a75641c 100644
--- a/apps/home/controller.h
+++ b/apps/home/controller.h
@@ -47,10 +47,19 @@ class Controller : public ViewController, public SimpleTableViewDataSource, publ
static constexpr KDCoordinate k_sideMargin = 4;
static constexpr KDCoordinate k_bottomMargin = 14;
static constexpr KDCoordinate k_indicatorMargin = 61;
+
+ #ifndef _FXCG
static constexpr int k_numberOfColumns = 3;
- static constexpr int k_maxNumberOfCells = 16;
static constexpr int k_cellHeight = 104;
static constexpr int k_cellWidth = 104;
+ #else
+ // A different screen resolution so different dimensions
+ static constexpr int k_numberOfColumns = 4;
+ static constexpr int k_cellHeight = 96;
+ static constexpr int k_cellWidth = 97;
+ #endif
+
+ static constexpr int k_maxNumberOfCells = 16;
ContentView m_view;
AppCell m_cells[k_maxNumberOfCells];
App * m_app;
diff --git a/apps/host_filemanager.cpp b/apps/host_filemanager.cpp
new file mode 100644
index 00000000000..86d5b4ca8d5
--- /dev/null
+++ b/apps/host_filemanager.cpp
@@ -0,0 +1,859 @@
+// #include
+// // #include "../apps_container.h"
+// #include "stddef.h"
+// #include "string.h"
+// #include "math.h"
+// #include "app.h"
+#include
+#include "apps_container.h"
+#include "global_preferences.h"
+// #include "../exam_mode_configuration.h"
+
+extern "C" {
+#include
+}
+
+#ifdef NSPIRE_NEWLIB
+const char * storage_name="/documents/nwstore.nws.tns";
+#else
+const char * storage_name="nwstore.nws";
+#endif
+
+const char * calc_storage_name="nwcalc.txt";
+void * storage_address(); // ion/src/simulator/shared/platform_info.cpp
+const char * retrieve_calc_history();
+#if defined _FXCG || defined NSPIRE_NEWLIB
+bool save_calc_history();
+void display_host_help();
+int load_state(const char * fname);
+#endif
+
+// Additional code by B. Parisse for host file system support and persistence
+// on Casio Graph 90/FXCG50 and TI Nspire
+void erase_record(const char * name){
+ unsigned char * ptr=(unsigned char *)storage_address();
+ for (ptr+=4;;){ // skip header
+ size_t L=ptr[1]*256+ptr[0];
+ if (L==0) return;
+ if (strcmp((const char *)ptr+2,name)==0){
+ unsigned char * newptr=ptr;
+ int S=0,erased=L;
+ ptr+=L;
+ for (;;){
+ L=ptr[1]*256+ptr[0];
+ if (L==0){
+ for (int i=0;inewptr+S)
+ memmove(newptr+S,ptr,L);
+ S+=L;
+ ptr+=L;
+ }
+ return;
+ }
+ ptr+=L;
+ }
+}
+
+
+// record filtering on read
+void filter(unsigned char * ptr){
+ unsigned char * newptr=ptr;
+ int S; ptr+=4;
+ for (S=4;;){
+ size_t L=ptr[1]*256+ptr[0];
+ if (L==0) break;
+ int l=strlen((const char *)ptr+2);
+ // filter py records
+ if (l>3 && strncmp((const char *)ptr+2+l-3,".py",3)==0){
+ // if (ptr>newptr+S)
+ memmove(newptr+S,ptr,L);
+ S+=L;
+ }
+#if 0 // def STRING_STORAGE
+ if (l>5 && strncmp((const char *)ptr+2+l-5,".func",5)==0){
+ int shift=l+4+13;
+ Ion::Storage::Record * record=(Ion::Storage::Record *)malloc(1024);
+ memcpy(record,ptr,L);
+ //ExpressionModelHandle
+ Poincare::Expression e=Poincare::Expression::Parse((const char *)ptr+shift,NULL);
+ //ExpressionModel::setContent(Ion::Storage::Record * record, const char * c, Context * context, CodePoint symbol);
+ Shared::ExpressionModel md;
+ Ion::Storage::Record::ErrorStatus err=md.setExpressionContent(record, e);
+ if (1){
+ // if (ptr>newptr+S)
+ int newL=record->value().size;
+ memmove(newptr+S,record,newL);
+ S+=newL;
+ }
+ free(record);
+ }
+#endif
+ ptr+=L;
+ }
+}
+
+
+#ifdef NSPIRE_NEWLIB
+#include "../../ion/src/simulator/fxcg/platform.h"
+#include "../../ion/src/simulator/fxcg/menuHandler.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include "../../ion/src/simulator/nspire/k_csdk.h"
+#include "../calculation/calculation_store.h"
+
+#define C_WHITE SDK_WHITE
+#define C_BLACK SDK_BLACK
+#define C_RED (31<<11)
+
+int do_getkey(){
+ os_wait_1ms(50);
+ return getkey(0);
+}
+
+void dtext(int x,int y,int fg,const char * s){
+ os_draw_string_medium(x,y,fg,SDK_WHITE,s);
+}
+
+void dclear(int c){
+ os_fill_rect(0,0,LCD_WIDTH_PX,LCD_HEIGHT_PX,c);
+}
+
+void dupdate(){
+ sync_screen();
+}
+
+const int storage_length=60000; // 60000 in Upsilon, 32768 in Epsilon
+// k_storageSize = 60000; in ion/include/ion/internal_storage.h
+extern void * last_calculation_history;
+
+int load_state(const char * fname){
+ FILE * f=fopen(fname,"rb");
+ if (f){
+ unsigned char * ptr=(unsigned char *)storage_address();
+ fread(ptr,1,storage_length,f);
+ fclose(f);
+#ifdef FILTER_STORE
+ filter(ptr);
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+int save_state(const char * fname){
+ save_calc_history();
+ if (1 || Ion::Storage::sharedStorage()->numberOfRecords()){
+ const unsigned char * ptr=(const unsigned char *)storage_address();
+ // find store size
+ int S=4;
+ for (ptr+=4;;){ // skip header
+ size_t L=ptr[1]*256+ptr[0];
+ ptr+=L;
+ S+=L;
+ if (L==0) break;
+ }
+ S = ((S+1023)/1024)*1024;
+#ifdef FILTER_STORE
+ // keep only python scripts
+ unsigned char * newptr=(unsigned char *) malloc(S);
+ bzero(newptr,S);
+ ptr=(const unsigned char *) storage_address();
+ memcpy(newptr,ptr,4); ptr+=4;
+ for (S=4;;){
+ size_t L=ptr[1]*256+ptr[0];
+ if (L==0) break;
+ int l=strlen((const char *)ptr+2);
+ if (l>3 && strncmp((const char *)ptr+2+l-3,".py",3)==0){
+ memcpy(newptr+S,ptr,L);
+ S+=L;
+ }
+ ptr+=L;
+ }
+ S = ((S+1023)/1024)*1024;
+ FILE * f;
+ f=fopen(fname,"wb");
+ if (f){
+ fwrite(newptr,S,1,f);
+ //fwrite(ptr+4,1,S-4,f);
+ fclose(f);
+ free(newptr);
+ return S;
+ }
+ free(newptr);
+ return 0;
+#else
+ ptr=(const unsigned char *)storage_address();
+ FILE * f;
+ f=fopen(fname,"wb");
+ if (f){
+ fwrite(ptr,S,1,f);
+ //fwrite(ptr+4,1,S-4,f);
+ fclose(f);
+ return S;
+ }
+ return 0;
+#endif
+ }
+ return 2;
+}
+
+#endif // NSPIRE_NEWLIB
+
+#ifdef _FXCG
+#include "../../ion/src/simulator/fxcg/platform.h"
+#include "../../ion/src/simulator/fxcg/menuHandler.h"
+#include "../calculation/calculation_store.h"
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#define KEY_CTRL_OK KEY_EXE
+int do_getkey(){
+ return getkey().key;
+}
+
+const int storage_length=60000; // 60000 in Upsilon, 32768 in Epsilon
+// k_storageSize = 60000; in ion/include/ion/internal_storage.h
+extern void * last_calculation_history;
+
+int load_state(const char * fname){
+ FILE * f=fopen(fname,"rb");
+ if (f){
+ unsigned char * ptr=(unsigned char *)storage_address();
+ ptr[3]=fgetc(f);
+ ptr[2]=fgetc(f);
+ ptr[1]=fgetc(f);
+ ptr[0]=fgetc(f);
+ fread(ptr+4,1,storage_length-4,f);
+ fclose(f);
+ return 1;
+ }
+ return 0;
+}
+
+int save_state(const char * fname){
+ save_calc_history();
+ if (Ion::Storage::sharedStorage()->numberOfRecords()){
+#if 0
+ unsigned short pFile[512];
+ convert(fname,pFile);
+ int hf = BFile_Open(pFile, BFile_WriteOnly); // Get handle
+ // cout << hf << endl << "f:" << filename << endl; Console_Disp();
+ if (hf<0){
+ int l=storage_length;
+ BFile_Create(pFile,0,&l);
+ hf = BFile_Open(pFile, BFile_WriteOnly);
+ }
+ if (hf < 0)
+ return 0;
+ int l=BFile_Write(hf,storage_address(),storage_length);
+ BFile_Close(hf);
+ if (l==storage_length)
+ return 1;
+ return -1;
+#else
+ const unsigned char * ptr=(const unsigned char *)storage_address();
+ // find store size
+ int S=4;
+ for (ptr+=4;;){ // skip header
+ size_t L=ptr[1]*256+ptr[0];
+ ptr+=L;
+ S+=L;
+ if (L==0) break;
+ }
+ S = ((S+1023)/1024)*1024;
+ FILE * f=fopen(fname,"wb");
+ if (f){
+ ptr=(const unsigned char *) storage_address();
+ fputc(ptr[3],f);
+ fputc(ptr[2],f);
+ fputc(ptr[1],f);
+ fputc(ptr[0],f);
+ //fwrite(ptr+4,1,S-4,f);
+ fwrite(ptr+4,S-4,1,f);
+ fclose(f);
+ return S;
+ }
+ return 0;
+#endif
+ }
+ return 2;
+}
+#endif // _FXCG
+
+const char * retrieve_calc_history(){
+#if defined _FXCG || defined NSPIRE_NEWLIB
+ static bool firstrun=true;
+ if (firstrun){
+#ifdef _FXCG
+ int l=gint_world_switch(GINT_CALL(load_state,storage_name));
+#else
+ int l=load_state(storage_name);
+#endif
+ if (l==0){
+ display_host_help();
+ // ((App*)m_app)->redraw();
+ }
+ firstrun=false;
+ }
+#endif
+ unsigned char * ptr=(unsigned char *)storage_address();
+ for (ptr+=4;;){ // skip header
+ size_t L=ptr[1]*256+ptr[0];
+ if (L==0) return 0;
+ if (strcmp((const char *)ptr+2,calc_storage_name)==0){
+ const char * buf=(const char *)ptr+2+strlen(calc_storage_name)+1;
+ return buf;
+ }
+ ptr += L;
+ }
+ return 0;
+}
+
+#if defined _FXCG || defined NSPIRE_NEWLIB
+bool save_calc_history(){
+ if (!last_calculation_history)
+ return false;
+ erase_record(calc_storage_name);
+ std::string s;
+ Calculation::CalculationStore * store=(Calculation::CalculationStore *) last_calculation_history;
+ int N=store->numberOfCalculations();
+ for (int i=N-1;i>=0;--i){
+ s += store->calculationAtIndex(i)->inputText();
+ s += '\n';
+ }
+ if (s.empty())
+ return false;
+ Ion::Storage::Record::ErrorStatus res= Ion::Storage::sharedStorage()->createRecordWithFullName(calc_storage_name,&s[0],s.size());
+ if (res==Ion::Storage::Record::ErrorStatus::NotEnoughSpaceAvailable)
+ return false;
+ return true;
+}
+
+void confirm_load_state(const char * buf){
+ dclear(C_WHITE);
+ dtext(1,1, C_BLACK, "Loading from state file");
+ dtext(1,17,C_BLACK,buf);
+ dtext(1,33,C_BLACK,"Current context will be lost!");
+ dtext(1,49,C_BLACK,"Press EXE to confirm");
+ dupdate();
+ int k=do_getkey();
+ if (k==KEY_EXE || k==KEY_CTRL_OK){
+#ifdef _FXCG
+ int l=gint_world_switch(GINT_CALL(load_state,buf));
+#else
+ int l=load_state(buf);
+#endif
+ char buf2[]="0";
+ buf2[0] += l;
+ if (l==0)
+ dtext(1,65,C_BLACK,"Error reading state");
+ if (l==1)
+ dtext(1,65,C_BLACK,"Success reading state");
+ dtext(1,81,C_BLACK,buf2);
+ dtext(1,97,C_BLACK,"Press any key");
+ dupdate();
+ do_getkey();
+ }
+}
+
+static void convert(const char * fname,unsigned short * pFile){
+ for ( ;*fname;++fname,++pFile)
+ *pFile=*fname;
+ *pFile=0;
+}
+
+struct file {
+ std::string s;
+ int length;
+ bool isdir;
+};
+
+void host_scripts(std::vector & v,const char * dirname,const char * extension){
+ v.clear();
+ file f={".._parent_dir",0,true};
+ if (strlen(dirname)>1)
+ v.push_back(f);
+ DIR *dp;
+ struct dirent *ep;
+ dp = opendir (dirname);
+ int l=extension?strlen(extension):0;
+ if (dp != NULL){
+ int t;
+ while ( (ep = readdir (dp)) ){
+ if (strlen(ep->d_name)>=1 && ep->d_name[0]=='.')
+ continue;
+ f.s=ep->d_name;
+ if (f.s=="@MainMem")
+ continue;
+#ifdef NSPIRE_NEWLIB
+ DIR * chk=opendir((dirname+f.s).c_str());
+ f.isdir=true;
+ if (chk)
+ closedir(chk);
+ else
+ f.isdir=false;
+#else
+ f.isdir=ep->d_type==DT_DIR;
+#endif
+#if 1
+ if (f.isdir)
+ f.length=0;
+ else {
+ struct stat st;
+ stat((dirname+f.s).c_str(), &st);
+ f.length = st.st_size;
+ if (f.length>=32768)
+ continue;
+ }
+#else
+ f.length=f.isdir?0:-1;
+#endif
+ if (f.isdir || !extension)
+ v.push_back(f);
+ else {
+ t=strlen(ep->d_name);
+ if (t>l && strncmp(ep->d_name+t-l,extension,l)==0)
+ v.push_back(f);
+ }
+ }
+ closedir (dp);
+ }
+}
+
+void nw_scripts(std::vector & v,const char * extension){
+ v.clear();
+#if 0
+ int n=Ion::Storage::sharedStorage()->numberOfRecords();
+ for (int i=0;irecordAtIndex(i).fullName());
+ }
+#else
+ const unsigned char * ptr=(const unsigned char *)storage_address();
+ int l=extension?strlen(extension):0;
+ for (ptr+=4;;){ // skip header
+ size_t L=ptr[1]*256+ptr[0];
+ ptr+=2;
+ if (L==0) break;
+ L-=2;
+ file f={(const char *)ptr,(int)L,false};
+ if (!extension)
+ v.push_back(f);
+ else {
+ int namesize=strlen((const char *)ptr);
+ if (namesize>l && strncmp((const char *)ptr+namesize-l,extension,l)==0)
+ v.push_back(f);
+ }
+ ptr+=L;
+ }
+#endif
+}
+
+int copy_nw_to_host(const char * nwname,const char * hostname){
+#ifdef NSPIRE_NEWLIB
+ int s=strlen(hostname);
+ if (s<4 || strncmp(hostname+s-4,".tns",4)){
+ std::string S(hostname);
+ S+=".tns";
+ return copy_nw_to_host(nwname,S.c_str());
+ }
+#endif
+ const unsigned char * ptr=(const unsigned char *)storage_address();
+ for (ptr+=4;;){ // skip header
+ size_t L=ptr[1]*256+ptr[0];
+ if (L==0) return 3; // not found
+ //dclear(C_WHITE);
+ //dtext(1,1,C_BLACK,ptr+2);
+ //dtext(1,17,C_BLACK,nwname);
+ //dupdate();
+ //getkey();
+ if (strcmp((const char *)ptr+2,nwname)){
+ ptr += L;
+ continue;
+ }
+ ptr+=2;
+ L-=2;
+ int l=strlen((const char *)ptr);
+ ptr += l+2;
+ L -= l;
+ L = 2*((L+1)/2);
+ FILE * f=fopen(hostname,"wb");
+ if (!f)
+ return 2;
+ fwrite(ptr,1,L,f);
+ fclose(f);
+ return 0;
+ }
+ return 1;
+}
+
+int copy_host_to_nw(const char * hostname,const char * nwname,int autoexec){
+ FILE * f=fopen(hostname,"rb");
+ if (!f)
+ return -1;
+ std::vector v(1,autoexec?1:0);
+ for (;;){
+ unsigned char c=fgetc(f);
+ if (feof(f)){
+ if (c>=' ' && c<=0x7e)
+ v.push_back(c);
+ break;
+ }
+ if (c==0xa && !v.empty() && v.back()==0xd)
+ v.back()=0xa;
+ else
+ v.push_back(c);
+ }
+ if (!v.empty() && v.back()!=0xa)
+ v.push_back(0xa);
+ v.push_back(0);
+ fclose(f);
+ if (Ion::Storage::sharedStorage()->hasRecord(Ion::Storage::sharedStorage()->recordNamed(nwname)))
+ Ion::Storage::sharedStorage()-> destroyRecord(Ion::Storage::sharedStorage()->recordNamed(nwname));
+ Ion::Storage::Record::ErrorStatus res= Ion::Storage::sharedStorage()->createRecordWithFullName(nwname,&v.front(),v.size());
+ if (res==Ion::Storage::Record::ErrorStatus::NotEnoughSpaceAvailable)
+ return -2;
+ return 0;
+}
+
+bool filesort(const file & a,const file & b){
+ if (a.isdir!=b.isdir)
+ return a.isdir;
+ return a.s v,w;
+#ifdef NSPIRE_NEWLIB
+ std::string hostdir="/documents/";
+#else
+ std::string hostdir="/";
+#endif
+ bool onlypy=true;
+ for (;;){
+ if (reload){
+ nw_scripts(v,onlypy?".py":0);
+ sort(v.begin(),v.end(),filesort);
+#ifdef NSPIRE_NEWLIB
+ host_scripts(w,hostdir.c_str(),onlypy?".py.tns":0);
+#else
+ host_scripts(w,hostdir.c_str(),onlypy?".py":0);
+#endif
+ sort(w.begin(),w.end(),filesort);
+ reload=false;
+ }
+ dclear(C_WHITE);
+ dtext(1,1, C_BLACK,"EXIT: leave; key 1 to 9: load state from file");
+#ifdef _FXCG
+ dtext(1,17,C_BLACK,"Cursor keys: move, /: rootdir, OPTN: all/py files");
+#else
+ dtext(1,17,C_BLACK,"Cursor keys: move, /: rootdir");
+#endif
+ dtext(1,33,C_BLACK,"EXE or STO key: copy selection from/to host");
+ dtext(1,49,C_BLACK,("Upsilon records Host "+hostdir).c_str());
+ int nitems=9;
+ if (posnw<0)
+ posnw=v.size()-1;
+ if (posnw>=int(v.size()))
+ posnw=0;
+ if (posnwstartnw+nitems)
+ startnw=posnw-4;
+ if (startnw>=int(v.size())-nitems)
+ startnw=v.size()-nitems;
+ if (startnw<0)
+ startnw=0;
+ if (v.empty())
+ nw=false;
+ for (int i=0;i<=nitems;++i){
+ int I=i+startnw;
+ if (I>=int(v.size()))
+ break;
+ dtext(1,65+16*i,(nw && I==posnw)?C_RED:C_BLACK,v[I].s.c_str());
+ char buf[256];
+ sprintf(buf,"%i",v[I].length);
+ dtext(90,65+16*i,(nw && I==posnw)?C_RED:C_BLACK,buf);
+ }
+ if (w.empty())
+ nw=true;
+ if (poshost<0)
+ poshost=w.size()-1;
+ if (poshost>=int(w.size()))
+ poshost=0;
+ if (poshoststarthost+nitems)
+ starthost=poshost-4;
+ if (starthost>=int(w.size())-nitems)
+ starthost=w.size()-nitems;
+ if (starthost<0)
+ starthost=0;
+ for (int i=0;i<=nitems;++i){
+ int I=i+starthost;
+ if (I>=int(w.size()))
+ break;
+ std::string fname=w[I].s;
+ if (fname.size()>16)
+ fname=fname.substr(0,16)+"...";
+ dtext(192,65+16*i,(!nw && I==poshost)?C_RED:C_BLACK,fname.c_str());
+ if (w[I].isdir)
+ dtext(154,65+16*i,(!nw && I==poshost)?C_RED:C_BLACK,"");
+ else {
+ char buf[256];
+ sprintf(buf,"%i",w[I].length);
+#ifdef _FXCG
+ dtext(340,65+16*i,(!nw && I==poshost)?C_RED:C_BLACK,buf);
+#else
+ dtext(285,65+16*i,(!nw && I==poshost)?C_RED:C_BLACK,buf);
+#endif
+ }
+ }
+ dupdate();
+ int key=do_getkey();
+ if (key==KEY_EXIT || key==KEY_MENU)
+ break;
+ if (key==KEY_OPTN || key=='\t'){
+ onlypy=!onlypy;
+ reload=true;
+ continue;
+ }
+ if (key==KEY_DIV){
+#ifdef NSPIRE_NEWLIB
+ hostdir="/documents/";
+#else
+ hostdir="/";
+#endif
+ reload=true;
+ continue;
+ }
+ if (key==KEY_DEL){
+ if (!nw && w[poshost].isdir) // can not remove directory
+ continue;
+ dclear(C_WHITE);
+ dtext(1,17,C_BLACK,nw?"About to suppress Upsilon record:":"About to suppress Host file:");
+ dtext(1,33,C_BLACK,(nw?v[posnw].s:w[poshost].s).c_str());
+ dtext(1,49,C_BLACK,"Press EXE or OK to confirm");
+ dupdate();
+ int ev=do_getkey();
+ if (ev!=KEY_EXE && ev!=KEY_CTRL_OK)
+ continue;
+ if (nw){
+#if 1
+ erase_record(v[posnw].s.c_str());
+#else
+ char buf[256];
+ strcpy(buf,v[posnw].s.c_str());
+ int l=strlen(buf)-4;
+ buf[l]=0;
+ Ion::Storage::sharedStorage()-> destroyRecordWithBaseNameAndExtension(buf,buf+l+1);
+#endif
+ }
+ else
+ remove((hostdir+w[poshost].s).c_str());
+ reload=true;
+ }
+ if (key==KEY_LEFT){
+ nw=true;
+ continue;
+ }
+ if (key==KEY_RIGHT){
+ nw=false;
+ continue;
+ }
+ if (key==KEY_PLUS){
+ if (nw)
+ posnw+=5;
+ else
+ poshost+=5;
+ continue;
+ }
+ if (key==KEY_MINUS){
+ if (nw)
+ posnw-=5;
+ else
+ poshost-=5;
+ continue;
+ }
+ if (key==KEY_DOWN){
+ if (nw)
+ ++posnw;
+ else
+ ++poshost;
+ continue;
+ }
+ if (key==KEY_UP){
+ if (nw)
+ --posnw;
+ else
+ --poshost;
+ continue;
+ }
+ int autoexec = key==KEY_EXE || key==KEY_CTRL_OK;
+ if (key==KEY_STORE || autoexec){
+ if (nw && posnw>=0 && posnw=0 && poshost=0;--j){
+ if (hostdir[j]=='/'){
+ hostdir=hostdir.substr(0,j+1);
+ break;
+ }
+ }
+ reload=true;
+ continue;
+ }
+ // lookup if poshost is in directories
+ if (w[poshost].isdir){
+ hostdir += w[poshost].s;
+ hostdir += "/";
+ reload=true;
+ continue;
+ }
+ size_t i;
+ std::string fname=w[poshost].s;
+#ifdef NSPIRE_NEWLIB
+ if (fname.size()>4 && fname.substr(fname.size()-4,4)==".tns")
+ fname=fname.substr(0,fname.size()-4);
+#endif
+ for (i=0;i12){
+ dclear(C_WHITE);
+ dtext(1,33,C_BLACK,"Host filename too long");
+ dtext(1,49,C_BLACK,fname.c_str());
+ dupdate();
+ do_getkey();
+ continue;
+ }
+ if (fname.size()>4 && fname.substr(fname.size()-4,4)==".nws")
+ confirm_load_state((hostdir+fname).c_str());
+ else {
+#ifdef _FXCG
+ gint_world_switch(GINT_CALL(copy_host_to_nw,(hostdir+fname).c_str(),nwname.c_str(),autoexec));
+#else
+ copy_host_to_nw((hostdir+w[poshost].s).c_str(),nwname.c_str(),autoexec);
+#endif
+ }
+ reload=true;
+ }
+ }
+ if (key>=KEY_1 && key<=KEY_9){
+#ifdef NSPIRE_NEWLIB
+ char buf[]="nwstate0.nws.tns";
+#else
+ char buf[]="nwstate0.nws";
+#endif
+ buf[7]='1'+(key-KEY_1);
+ confirm_load_state(buf);
+ reload=true;
+ }
+ }
+}
+#endif // FXCG || NSPIRE
\ No newline at end of file
diff --git a/apps/main.cpp b/apps/main.cpp
index b73b73e77be..ec1db8b8073 100644
--- a/apps/main.cpp
+++ b/apps/main.cpp
@@ -1,6 +1,7 @@
#include "apps_container.h"
#include "global_preferences.h"
#include
+#include
#define DUMMY_MAIN 0
#if DUMMY_MAIN
@@ -50,13 +51,29 @@ void ion_main(int argc, const char * const argv[]) {
}
continue;
}
+
+ /* Option should be given at run-time:
+ * $ ./epsilon.elf --open-app code
+ */
+ const char * appNames[] = {"home", EPSILON_APPS_NAMES};
+ if (strcmp(argv[i], "--open-app") == 0 && argc > i+1) {
+ const char * requestedAppName = argv[i+1];
+ for (int j = 0; j < AppsContainer::sharedAppsContainer()->numberOfApps(); j++) {
+ App::Snapshot * snapshot = AppsContainer::sharedAppsContainer()->appSnapshotAtIndex(j);
+ if (strcmp(requestedAppName, appNames[j]) == 0) {
+ AppsContainer::sharedAppsContainer()->setStartApp(snapshot);
+ break;
+ }
+ }
+ continue;
+ }
+
/* Option should be given at run-time:
* $ ./epsilon.elf --[app_name]-[option] [arguments]
* For example:
* $ make -j8 PLATFORM=emscripten EPSILON_APPS=code
* $ ./epsilon.elf --code-script hello_world.py:print("hello") --code-lock-on-console
*/
- const char * appNames[] = {"home", EPSILON_APPS_NAMES};
for (int j = 0; j < AppsContainer::sharedAppsContainer()->numberOfApps(); j++) {
App::Snapshot * snapshot = AppsContainer::sharedAppsContainer()->appSnapshotAtIndex(j);
// Compare name in order to find if the firsts chars which are different are NULL and '-'
diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp
index ad82cb08158..1d4900c9785 100644
--- a/apps/math_toolbox.cpp
+++ b/apps/math_toolbox.cpp
@@ -30,7 +30,7 @@ const ToolboxMessageTree calculChildren[] = {
const ToolboxMessageTree complexChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::AbsCommandWithArg,I18n::Message::ComplexAbsoluteValue),
- ToolboxMessageTree::Leaf(I18n::Message::ArgCommandWithArg, I18n::Message::Agument),
+ ToolboxMessageTree::Leaf(I18n::Message::ArgCommandWithArg, I18n::Message::Argument),
ToolboxMessageTree::Leaf(I18n::Message::ReCommandWithArg, I18n::Message::RealPart),
ToolboxMessageTree::Leaf(I18n::Message::ImCommandWithArg, I18n::Message::ImaginaryPart),
ToolboxMessageTree::Leaf(I18n::Message::ConjCommandWithArg, I18n::Message::Conjugate)
@@ -67,13 +67,10 @@ const ToolboxMessageTree arithmeticChildren[] = {
};
const ToolboxMessageTree matricesChildren[] = {
- ToolboxMessageTree::Leaf(I18n::Message::MatrixCommandWithArg, I18n::Message::NewMatrix, false, I18n::Message::MatrixCommand),
- ToolboxMessageTree::Leaf(I18n::Message::IndentityCommandWithArg, I18n::Message::Identity),
- ToolboxMessageTree::Leaf(I18n::Message::InverseCommandWithArg, I18n::Message::Inverse),
ToolboxMessageTree::Leaf(I18n::Message::DeterminantCommandWithArg, I18n::Message::Determinant),
- ToolboxMessageTree::Leaf(I18n::Message::TransposeCommandWithArg, I18n::Message::Transpose),
+ ToolboxMessageTree::Leaf(I18n::Message::InverseCommandWithArg, I18n::Message::Inverse),
+ ToolboxMessageTree::Leaf(I18n::Message::IndentityCommandWithArg, I18n::Message::Identity),
ToolboxMessageTree::Leaf(I18n::Message::TraceCommandWithArg, I18n::Message::Trace),
- ToolboxMessageTree::Leaf(I18n::Message::DimensionCommandWithArg, I18n::Message::Dimension),
ToolboxMessageTree::Leaf(I18n::Message::RowEchelonFormCommandWithArg, I18n::Message::RowEchelonForm),
ToolboxMessageTree::Leaf(I18n::Message::ReducedRowEchelonFormCommandWithArg, I18n::Message::ReducedRowEchelonForm)
};
@@ -84,6 +81,14 @@ const ToolboxMessageTree vectorsChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::NormVectorCommandWithArg, I18n::Message::NormVector),
};
+const ToolboxMessageTree matricesAndVectorsChildren[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::MatrixCommandWithArg, I18n::Message::NewMatrix, false, I18n::Message::MatrixCommand),
+ ToolboxMessageTree::Leaf(I18n::Message::TransposeCommandWithArg, I18n::Message::Transpose),
+ ToolboxMessageTree::Leaf(I18n::Message::DimensionCommandWithArg, I18n::Message::Dimension),
+ ToolboxMessageTree::Node(I18n::Message::Matrices, matricesChildren),
+ ToolboxMessageTree::Node(I18n::Message::Vectors, vectorsChildren)
+};
+
#if LIST_ARE_DEFINED
const ToolboxMessageTree listsChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::SortCommandWithArg, I18n::Message::Sort),
@@ -252,7 +257,7 @@ const ToolboxMessageTree unitEnergyElectronVoltChildren[] = {
};
const ToolboxMessageTree unitEnergyChildren[] = {
ToolboxMessageTree::Node(I18n::Message::UnitEnergyJouleMenu, unitEnergyJouleChildren),
- ToolboxMessageTree::Node(I18n::Message::UnitEnergyEletronVoltMenu, unitEnergyElectronVoltChildren)};
+ ToolboxMessageTree::Node(I18n::Message::UnitEnergyElectronVoltMenu, unitEnergyElectronVoltChildren)};
const ToolboxMessageTree unitPowerWattChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::UnitPowerWattMicroSymbol, I18n::Message::UnitPowerWattMicro),
@@ -711,6 +716,54 @@ const ToolboxMessageTree Electromagnetism[] = {
};
+const ToolboxMessageTree Resistivity[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::Silver, I18n::Message::Rstvt_Silver, false, I18n::Message::Rstvt_Silver),
+ ToolboxMessageTree::Leaf(I18n::Message::Copper, I18n::Message::Rstvt_Copper, false, I18n::Message::Rstvt_Copper),
+ ToolboxMessageTree::Leaf(I18n::Message::Gold, I18n::Message::Rstvt_Gold, false, I18n::Message::Rstvt_Gold),
+ ToolboxMessageTree::Leaf(I18n::Message::Aluminium, I18n::Message::Rstvt_Aluminium, false, I18n::Message::Rstvt_Aluminium),
+ ToolboxMessageTree::Leaf(I18n::Message::Calcium, I18n::Message::Rstvt_Calcium, false, I18n::Message::Rstvt_Calcium),
+ ToolboxMessageTree::Leaf(I18n::Message::Tungsten, I18n::Message::Rstvt_Tungsten, false, I18n::Message::Rstvt_Tungsten),
+ ToolboxMessageTree::Leaf(I18n::Message::Zinc, I18n::Message::Rstvt_Zinc, false, I18n::Message::Rstvt_Zinc),
+ ToolboxMessageTree::Leaf(I18n::Message::Cobalt, I18n::Message::Rstvt_Cobalt, false, I18n::Message::Rstvt_Cobalt),
+ ToolboxMessageTree::Leaf(I18n::Message::Nickel, I18n::Message::Rstvt_Nickel, false, I18n::Message::Rstvt_Nickel),
+ ToolboxMessageTree::Leaf(I18n::Message::Lithium, I18n::Message::Rstvt_Lithium, false, I18n::Message::Rstvt_Lithium),
+ ToolboxMessageTree::Leaf(I18n::Message::Iron, I18n::Message::Rstvt_Iron, false, I18n::Message::Rstvt_Iron),
+ ToolboxMessageTree::Leaf(I18n::Message::Platinum, I18n::Message::Rstvt_Platinum, false, I18n::Message::Rstvt_Platinum),
+ ToolboxMessageTree::Leaf(I18n::Message::Tin, I18n::Message::Rstvt_Tin, false, I18n::Message::Rstvt_Tin),
+ ToolboxMessageTree::Leaf(I18n::Message::Sea_water, I18n::Message::Rstvt_Sea_water, false, I18n::Message::Rstvt_Sea_water),
+ ToolboxMessageTree::Leaf(I18n::Message::Water, I18n::Message::Rstvt_Water, false, I18n::Message::Rstvt_Water),
+ ToolboxMessageTree::Leaf(I18n::Message::Air, I18n::Message::Rstvt_Air, false, I18n::Message::Rstvt_Air),
+ ToolboxMessageTree::Leaf(I18n::Message::Wood, I18n::Message::Rstvt_Wood, false, I18n::Message::Rstvt_Wood),
+ ToolboxMessageTree::Leaf(I18n::Message::Glass, I18n::Message::Rstvt_Glass, false, I18n::Message::Rstvt_Glass)
+};
+
+const ToolboxMessageTree Conductivity[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::Silver, I18n::Message::Cndcvt_Silver, false, I18n::Message::Cndcvt_Silver),
+ ToolboxMessageTree::Leaf(I18n::Message::Copper, I18n::Message::Cndcvt_Copper, false, I18n::Message::Cndcvt_Copper),
+ ToolboxMessageTree::Leaf(I18n::Message::Gold, I18n::Message::Cndcvt_Gold, false, I18n::Message::Cndcvt_Gold),
+ ToolboxMessageTree::Leaf(I18n::Message::Aluminium, I18n::Message::Cndcvt_Aluminium, false, I18n::Message::Cndcvt_Aluminium),
+ ToolboxMessageTree::Leaf(I18n::Message::Calcium, I18n::Message::Cndcvt_Calcium, false, I18n::Message::Cndcvt_Calcium),
+ ToolboxMessageTree::Leaf(I18n::Message::Tungsten, I18n::Message::Cndcvt_Tungsten, false, I18n::Message::Cndcvt_Tungsten),
+ ToolboxMessageTree::Leaf(I18n::Message::Zinc, I18n::Message::Cndcvt_Zinc, false, I18n::Message::Cndcvt_Zinc),
+ ToolboxMessageTree::Leaf(I18n::Message::Cobalt, I18n::Message::Cndcvt_Cobalt, false, I18n::Message::Cndcvt_Cobalt),
+ ToolboxMessageTree::Leaf(I18n::Message::Nickel, I18n::Message::Cndcvt_Nickel, false, I18n::Message::Cndcvt_Nickel),
+ ToolboxMessageTree::Leaf(I18n::Message::Lithium, I18n::Message::Cndcvt_Lithium, false, I18n::Message::Cndcvt_Lithium),
+ ToolboxMessageTree::Leaf(I18n::Message::Iron, I18n::Message::Cndcvt_Iron, false, I18n::Message::Cndcvt_Iron),
+ ToolboxMessageTree::Leaf(I18n::Message::Platinum, I18n::Message::Cndcvt_Platinum, false, I18n::Message::Cndcvt_Platinum),
+ ToolboxMessageTree::Leaf(I18n::Message::Tin, I18n::Message::Cndcvt_Tin, false, I18n::Message::Cndcvt_Tin),
+ ToolboxMessageTree::Leaf(I18n::Message::Sea_water, I18n::Message::Cndcvt_Sea_water, false, I18n::Message::Cndcvt_Sea_water),
+ ToolboxMessageTree::Leaf(I18n::Message::Water, I18n::Message::Cndcvt_Water, false, I18n::Message::Cndcvt_Water),
+ ToolboxMessageTree::Leaf(I18n::Message::Air, I18n::Message::Cndcvt_Air, false, I18n::Message::Cndcvt_Air),
+ ToolboxMessageTree::Leaf(I18n::Message::Wood, I18n::Message::Cndcvt_Wood, false, I18n::Message::Cndcvt_Wood),
+ ToolboxMessageTree::Leaf(I18n::Message::Glass, I18n::Message::Cndcvt_Glass, false, I18n::Message::Cndcvt_Glass)
+};
+
+const ToolboxMessageTree Electricity[] = {
+ ToolboxMessageTree::Leaf(I18n::Message::ElementalChargeTag, I18n::Message::ElementalCharge, false, I18n::Message::ElementalCharge),
+ ToolboxMessageTree::Node(I18n::Message::ResistivityConstants, Resistivity),
+ ToolboxMessageTree::Node(I18n::Message::ConductivityConstants, Conductivity)
+};
+
const ToolboxMessageTree ParticleMass[] = {
ToolboxMessageTree::Leaf(I18n::Message::ElectronMassTag, I18n::Message::ElectronMass, false, I18n::Message::ElectronMass),
ToolboxMessageTree::Leaf(I18n::Message::MuonMassTag, I18n::Message::MuonMass, false, I18n::Message::MuonMass),
@@ -788,6 +841,7 @@ const ToolboxMessageTree PlanckUnits[] = {
const ToolboxMessageTree Physics[] = {
ToolboxMessageTree::Node(I18n::Message::FundamentalConstants, FundamentalConstants),
ToolboxMessageTree::Node(I18n::Message::Electromagnetism, Electromagnetism),
+ ToolboxMessageTree::Node(I18n::Message::Electricity, Electricity),
ToolboxMessageTree::Node(I18n::Message::NuclearConstants, Nuclear),
ToolboxMessageTree::Node(I18n::Message::Thermodynamics, Thermodynamics),
ToolboxMessageTree::Node(I18n::Message::Gravitation, Gravitation),
@@ -800,20 +854,23 @@ const ToolboxMessageTree Physics[] = {
const ToolboxMessageTree menu[] = {
+ #ifdef _FXCG
+ // There is no factorial button on the fx-CG calculators
+ ToolboxMessageTree::Leaf(I18n::Message::FactorialCommandWithArg, I18n::Message::Factorial, false, I18n::Message::FactorialCommand),
+ #endif
ToolboxMessageTree::Leaf(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue),
ToolboxMessageTree::Leaf(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot),
ToolboxMessageTree::Leaf(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm),
ToolboxMessageTree::Node(I18n::Message::Calculation, calculChildren),
ToolboxMessageTree::Node(I18n::Message::ComplexNumber, complexChildren),
- ToolboxMessageTree::Node(I18n::Message::Combinatorics, combinatoricsChildren),
- ToolboxMessageTree::Node(I18n::Message::Probability, probabilityChildren),
+ ToolboxMessageTree::Node(I18n::Message::Unit, unitChildren),
ToolboxMessageTree::Node(I18n::Message::Arithmetic, arithmeticChildren),
- ToolboxMessageTree::Node(I18n::Message::Matrices, matricesChildren),
- ToolboxMessageTree::Node(I18n::Message::Vectors, vectorsChildren),
+ ToolboxMessageTree::Node(I18n::Message::MatricesAndVectors, matricesAndVectorsChildren),
+ ToolboxMessageTree::Node(I18n::Message::Probability, probabilityChildren),
#if LIST_ARE_DEFINED
ToolboxMessageTree::Node(I18n::Message::Lists,listsChildren),
#endif
- ToolboxMessageTree::Node(I18n::Message::Unit, unitChildren),
+ ToolboxMessageTree::Node(I18n::Message::Combinatorics, combinatoricsChildren),
ToolboxMessageTree::Node(I18n::Message::RandomAndApproximation, randomAndApproximationChildren),
ToolboxMessageTree::Node(I18n::Message::HyperbolicTrigonometry, trigonometryChildren),
ToolboxMessageTree::Node(I18n::Message::Fluctuation, predictionChildren),
@@ -826,9 +883,13 @@ const ToolboxMessageTree toolboxModel = ToolboxMessageTree::Node(I18n::Message::
MathToolbox::MathToolbox() :
Toolbox(nullptr, rootModel()->label())
{
+ for (int i=0; i < k_maxNumberOfDisplayedRows; i++) {
+ m_leafCells[i].setMessageFont(KDFont::LargeFont);
+ m_nodeCells[i].setMessageFont(KDFont::LargeFont);
+ }
}
-bool MathToolbox::selectLeaf(int selectedRow) {
+bool MathToolbox::selectLeaf(int selectedRow, bool quitToolbox) {
ToolboxMessageTree * messageTree = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(selectedRow);
m_selectableTableView.deselectTable();
@@ -851,12 +912,12 @@ const ToolboxMessageTree * MathToolbox::rootModel() const {
return &toolboxModel;
}
-MessageTableCellWithMessage * MathToolbox::leafCellAtIndex(int index) {
+MessageTableCellWithMessage * MathToolbox::leafCellAtIndex(int index) {
assert(index >= 0 && index < k_maxNumberOfDisplayedRows);
return &m_leafCells[index];
}
-MessageTableCellWithChevron* MathToolbox::nodeCellAtIndex(int index) {
+MessageTableCellWithChevron * MathToolbox::nodeCellAtIndex(int index) {
assert(index >= 0 && index < k_maxNumberOfDisplayedRows);
return &m_nodeCells[index];
}
diff --git a/apps/math_toolbox.h b/apps/math_toolbox.h
index 2ade3318f62..936cf42c94e 100644
--- a/apps/math_toolbox.h
+++ b/apps/math_toolbox.h
@@ -9,16 +9,16 @@ class MathToolbox : public Toolbox {
MathToolbox();
const ToolboxMessageTree * rootModel() const override;
protected:
- bool selectLeaf(int selectedRow) override;
- MessageTableCellWithMessage * leafCellAtIndex(int index) override;
- MessageTableCellWithChevron* nodeCellAtIndex(int index) override;
+ bool selectLeaf(int selectedRow, bool quitToolbox) override;
+ MessageTableCellWithMessage * leafCellAtIndex(int index) override;
+ MessageTableCellWithChevron * nodeCellAtIndex(int index) override;
int maxNumberOfDisplayedRows() override;
constexpr static int k_maxNumberOfDisplayedRows = 6; // = 240/40
private:
int indexAfterFork() const override;
- MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows];
- MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows];
+ MessageTableCellWithMessage m_leafCells[k_maxNumberOfDisplayedRows];
+ MessageTableCellWithChevron m_nodeCells[k_maxNumberOfDisplayedRows];
};
#endif
diff --git a/apps/math_variable_box_controller.cpp b/apps/math_variable_box_controller.cpp
index f8e01ea9f33..fb39e3b3958 100644
--- a/apps/math_variable_box_controller.cpp
+++ b/apps/math_variable_box_controller.cpp
@@ -98,7 +98,7 @@ int MathVariableBoxController::reusableCellCount(int type) {
void MathVariableBoxController::willDisplayCellForIndex(HighlightCell * cell, int index) {
if (m_currentPage == Page::RootMenu) {
I18n::Message label = nodeLabelAtIndex(index);
- MessageTableCell * myCell = (MessageTableCell *)cell;
+ MessageTableCell<> * myCell = (MessageTableCell<> *)cell;
myCell->setMessage(label);
myCell->reloadCell();
return;
@@ -124,7 +124,7 @@ void MathVariableBoxController::willDisplayCellForIndex(HighlightCell * cell, in
symbolName,
Shared::Sequence::k_maxNameWithArgumentSize
);
- Expression symbolExpression = Expression::ParseAndSimplify(symbolName, AppsContainer::sharedAppsContainer()->globalContext(), Poincare::Preferences::sharedPreferences()->complexFormat(), Poincare::Preferences::sharedPreferences()->angleUnit(), GlobalPreferences::sharedGlobalPreferences()->unitFormat());
+ Expression symbolExpression = Expression::Parse(symbolName, AppsContainer::sharedAppsContainer()->globalContext());
symbolLayout = symbolExpression.createLayout(Poincare::Preferences::sharedPreferences()->displayMode(), Poincare::Preferences::sharedPreferences()->numberOfSignificantDigits());
}
if (symbolLayout.isUninitialized()) {
@@ -158,7 +158,7 @@ ExpressionTableCellWithExpression * MathVariableBoxController::leafCellAtIndex(i
return &m_leafCells[index];
}
-MessageTableCellWithChevron * MathVariableBoxController::nodeCellAtIndex(int index) {
+MessageTableCellWithChevron<> * MathVariableBoxController::nodeCellAtIndex(int index) {
assert(index >= 0 && index < k_numberOfMenuRows);
return &m_nodeCells[index];
}
@@ -193,7 +193,7 @@ bool MathVariableBoxController::returnToPreviousMenu() {
return AlternateEmptyNestedMenuController::returnToPreviousMenu();
}
-bool MathVariableBoxController::selectLeaf(int selectedRow) {
+bool MathVariableBoxController::selectLeaf(int selectedRow, bool quitToolbox) {
if (isDisplayingEmptyController()) {
/* We do not want to handle OK/EXE events in that case. */
return false;
diff --git a/apps/math_variable_box_controller.h b/apps/math_variable_box_controller.h
index 86f968303a5..cf2f2fb0bb2 100644
--- a/apps/math_variable_box_controller.h
+++ b/apps/math_variable_box_controller.h
@@ -37,12 +37,12 @@ class MathVariableBoxController : public AlternateEmptyNestedMenuController {
constexpr static int k_numberOfMenuRows = 3;
constexpr static KDCoordinate k_leafMargin = 20;
ExpressionTableCellWithExpression * leafCellAtIndex(int index) override;
- MessageTableCellWithChevron * nodeCellAtIndex(int index) override;
+ MessageTableCellWithChevron<> * nodeCellAtIndex(int index) override;
Page pageAtIndex(int index);
void setPage(Page page);
bool selectSubMenu(int selectedRow) override;
bool returnToPreviousMenu() override;
- bool selectLeaf(int selectedRow) override;
+ bool selectLeaf(int selectedRow, bool quitToolbox) override;
I18n::Message nodeLabelAtIndex(int index);
Poincare::Layout expressionLayoutForRecord(Ion::Storage::Record record, int index);
const char * extension() const;
@@ -53,7 +53,7 @@ class MathVariableBoxController : public AlternateEmptyNestedMenuController {
Page m_currentPage;
Page m_lockPageDelete;
ExpressionTableCellWithExpression m_leafCells[k_maxNumberOfDisplayedRows];
- MessageTableCellWithChevron m_nodeCells[k_numberOfMenuRows];
+ MessageTableCellWithChevron<> m_nodeCells[k_numberOfMenuRows];
MathVariableBoxEmptyController m_emptyViewController;
// Layout memoization
// TODO: make a helper doing the RingMemoizationOfConsecutiveObjets to factorize this code and ExpressionModelStore code
diff --git a/apps/math_variable_box_empty_controller.cpp b/apps/math_variable_box_empty_controller.cpp
index 4c832c19557..88a306fbc77 100644
--- a/apps/math_variable_box_empty_controller.cpp
+++ b/apps/math_variable_box_empty_controller.cpp
@@ -5,7 +5,7 @@
MathVariableBoxEmptyController::MathVariableBoxEmptyView::MathVariableBoxEmptyView() :
ModalViewEmptyView(),
- m_layoutExample(0.5f, 0.5f, KDColorBlack, Palette::WallScreen)
+ m_layoutExample(0.5f, 0.5f, Palette::PrimaryText, Palette::WallScreen)
{
initMessageViews();
}
diff --git a/apps/on_boarding/app.cpp b/apps/on_boarding/app.cpp
index 3e914f7d9d4..1b789338b92 100644
--- a/apps/on_boarding/app.cpp
+++ b/apps/on_boarding/app.cpp
@@ -18,22 +18,14 @@ App::App(Snapshot * snapshot) :
m_localizationController(&m_modalViewController, Metric::CommonTopMargin, LocalizationController::Mode::Language),
m_logoController()
{
-}
-
-int App::numberOfTimers() {
- return firstResponder() == &m_logoController;
-}
-
-Timer * App::timerAtIndex(int i) {
- assert(i == 0);
- return &m_logoController;
+ AppsContainer::sharedAppsContainer()->addTimer(&m_logoController);
}
bool App::processEvent(Ion::Events::Event e) {
if (e == Ion::Events::Home) {
return true;
}
- if (e == Ion::Events::OnOff) {
+ if (e == Ion::Events::OnOff && !GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
Ion::Power::standby(); // Force a core reset to exit
}
return ::App::processEvent(e);
diff --git a/apps/on_boarding/app.h b/apps/on_boarding/app.h
index d9dbe43a487..38233c5bdf4 100644
--- a/apps/on_boarding/app.h
+++ b/apps/on_boarding/app.h
@@ -15,9 +15,6 @@ class App : public ::App {
App * unpack(Container * container) override;
Descriptor * descriptor() override;
};
-
- int numberOfTimers() override;
- Timer * timerAtIndex(int i) override;
bool processEvent(Ion::Events::Event) override;
void didBecomeActive(Window * window) override;
private:
diff --git a/apps/on_boarding/logo_controller.cpp b/apps/on_boarding/logo_controller.cpp
index 13df87e4d01..fb870c3829d 100644
--- a/apps/on_boarding/logo_controller.cpp
+++ b/apps/on_boarding/logo_controller.cpp
@@ -16,7 +16,7 @@ LogoController::LogoController() :
}
bool LogoController::fire() {
- Container::activeApp()->dismissModalViewController();
+ Container::activeApp()->dismissModalViewController();
return true;
}
@@ -41,7 +41,6 @@ void LogoController::viewWillAppear() {
if (!backlightInitialized) {
Ion::Backlight::init();
}
- ViewController::viewWillAppear();
}
void LogoController::viewDidDisappear() {
@@ -53,6 +52,7 @@ void LogoController::viewDidDisappear() {
AppsContainer::sharedAppsContainer()->activateExamMode(GlobalPreferences::sharedGlobalPreferences()->examMode());
}
}
+ AppsContainer::sharedAppsContainer()->removeTimer(this);
ViewController::viewDidDisappear();
}
diff --git a/apps/on_boarding/logo_icon.png b/apps/on_boarding/logo_icon.png
index 0dc9c6174e3..bfec4d823a2 100644
Binary files a/apps/on_boarding/logo_icon.png and b/apps/on_boarding/logo_icon.png differ
diff --git a/apps/on_boarding/prompt_controller.cpp b/apps/on_boarding/prompt_controller.cpp
index e938a43a0c8..773a7704198 100644
--- a/apps/on_boarding/prompt_controller.cpp
+++ b/apps/on_boarding/prompt_controller.cpp
@@ -4,8 +4,8 @@
namespace OnBoarding {
-PromptController::MessageViewWithSkip::MessageViewWithSkip(I18n::Message * messages, KDColor * colors, uint8_t numberOfMessages) :
- MessageView(messages, colors, numberOfMessages),
+PromptController::MessageViewWithSkip::MessageViewWithSkip(I18n::Message * messages, KDColor * fgcolors, KDColor * bgcolors, uint8_t numberOfMessages) :
+ MessageView(messages, fgcolors, bgcolors, numberOfMessages),
m_skipView(KDFont::SmallFont, I18n::Message::Skip, 1.0f, 0.5f),
m_okView()
{
@@ -42,9 +42,9 @@ void PromptController::MessageViewWithSkip::layoutSubviews(bool force) {
m_okView.setFrame(KDRect(width - okSize.width()-k_okMargin, height-okSize.height()-k_okMargin, okSize), force);
}
-PromptController::PromptController(I18n::Message * messages, KDColor * colors, uint8_t numberOfMessages) :
+PromptController::PromptController(I18n::Message * messages, KDColor * fgcolors, KDColor * bgcolors, uint8_t numberOfMessages) :
ViewController(nullptr),
- m_messageViewWithSkip(messages, colors, numberOfMessages)
+ m_messageViewWithSkip(messages, fgcolors, bgcolors, numberOfMessages)
{
}
diff --git a/apps/on_boarding/prompt_controller.h b/apps/on_boarding/prompt_controller.h
index b0ce7b61554..eb251868bf5 100644
--- a/apps/on_boarding/prompt_controller.h
+++ b/apps/on_boarding/prompt_controller.h
@@ -10,13 +10,13 @@ namespace OnBoarding {
class PromptController : public ViewController {
public:
- PromptController(I18n::Message * messages, KDColor * colors, uint8_t numberOfMessages);
+ PromptController(I18n::Message * messages, KDColor * fgcolors, KDColor * bgcolors, uint8_t numberOfMessages);
View * view() override { return &m_messageViewWithSkip; }
bool handleEvent(Ion::Events::Event event) override;
private:
class MessageViewWithSkip : public MessageView {
public:
- MessageViewWithSkip(I18n::Message * messages, KDColor * colors, uint8_t numberOfMessages);
+ MessageViewWithSkip(I18n::Message * messages, KDColor * fgcolors, KDColor * bgcolors, uint8_t numberOfMessages);
protected:
int numberOfSubviews() const override;
View * subviewAtIndex(int index) override;
diff --git a/apps/probability/app.h b/apps/probability/app.h
index d93905c4690..2e8e3fddfd4 100644
--- a/apps/probability/app.h
+++ b/apps/probability/app.h
@@ -57,7 +57,7 @@ class App : public Shared::TextFieldDelegateApp {
void deleteDistributionAndCalculation();
void initializeDistributionAndCalculation();
-#if __EMSCRIPTEN__
+#if (defined __EMSCRIPTEN__) || (defined _FXCG)
constexpr static int k_distributionAlignments[] = {alignof(BinomialDistribution),alignof(ExponentialDistribution), alignof(NormalDistribution), alignof(PoissonDistribution), alignof(UniformDistribution), 0};
constexpr static size_t k_distributionAlignment = max(k_distributionAlignments);
constexpr static int k_calculationAlignments[] = {alignof(LeftIntegralCalculation),alignof(FiniteIntegralCalculation), alignof(RightIntegralCalculation), 0};
diff --git a/apps/probability/calculation_controller.cpp b/apps/probability/calculation_controller.cpp
index 2d4ddd1b639..3b69a7b3f7e 100644
--- a/apps/probability/calculation_controller.cpp
+++ b/apps/probability/calculation_controller.cpp
@@ -183,7 +183,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
constexpr int precision = Preferences::LargeNumberOfSignificantDigits;
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
char buffer[bufferSize];
- // FIXME: Leo has not decided yet if we should use the prefered mode instead of always using scientific mode
+ // FIXME: Leo has not decided yet if we should use the preferred mode instead of always using scientific mode
PoincareHelpers::ConvertFloatToTextWithDisplayMode(m_calculation->parameterAtIndex(i-1), buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
field->setText(buffer);
}
diff --git a/apps/probability/distribution/distribution.cpp b/apps/probability/distribution/distribution.cpp
index aae3631d01a..d9872d177de 100644
--- a/apps/probability/distribution/distribution.cpp
+++ b/apps/probability/distribution/distribution.cpp
@@ -134,7 +134,7 @@ double Distribution::cumulativeDistributiveInverseForProbabilityUsingIncreasingF
* the given ax bx bounds */
if (!(std::isnan(result.x2()) || std::fabs(result.x2()) <= FLT_EPSILON || std::fabs(result.x1()- ax) < FLT_EPSILON || std::fabs(result.x1() - bx) < FLT_EPSILON)) {
/* TODO We would like to put this as an assertion, but sometimes we do get
- * false result: we replace them with inf to make the problem obvisous to
+ * false result: we replace them with inf to make the problem obvious to
* the student. */
return *probability > 0.5 ? INFINITY : -INFINITY;
}
diff --git a/apps/probability/distribution/student_distribution.cpp b/apps/probability/distribution/student_distribution.cpp
index bdeb1acf84a..a4e6617d86d 100644
--- a/apps/probability/distribution/student_distribution.cpp
+++ b/apps/probability/distribution/student_distribution.cpp
@@ -33,7 +33,7 @@ double StudentDistribution::cumulativeDistributiveFunctionAtAbscissa(double x) c
if (std::isinf(x)) {
return x > 0 ? 1.0 : 0.0;
}
- /* TODO There are some computation errors, where the probability falsly jumps to 1.
+ /* TODO There are some computation errors, where the probability falsy jumps to 1.
* k = 0.001 and P(x < 42000000) (for 41000000 it is around 0.5)
* k = 0.01 and P(x < 8400000) (for 41000000 it is around 0.6) */
const double k = m_parameter1;
diff --git a/apps/reader/Makefile b/apps/reader/Makefile
new file mode 100644
index 00000000000..0af0aefdf41
--- /dev/null
+++ b/apps/reader/Makefile
@@ -0,0 +1,21 @@
+apps += Reader::App
+app_headers += apps/reader/app.h
+
+SFLAGS += -DHAS_READER
+
+app_sreader_src = $(addprefix apps/reader/,\
+ app.cpp \
+ list_book_controller.cpp \
+ utility.cpp \
+ read_book_controller \
+ word_wrap_view.cpp \
+ tex_parser.cpp \
+)
+
+apps_src += $(app_sreader_src)
+
+app_images += apps/reader/reader_icon.png
+
+i18n_files += $(call i18n_without_universal_for,reader/base)
+
+$(eval $(call depends_on_image,apps/reader/app.cpp,apps/reader/reader_icon.png))
diff --git a/apps/reader/README.md b/apps/reader/README.md
new file mode 100644
index 00000000000..1405f99e8f1
--- /dev/null
+++ b/apps/reader/README.md
@@ -0,0 +1,29 @@
+# Thanks
+Thanks to [Gabriel79](https://github.com/Gabriel79) for the original reader app, his source code available [here](https://github.com/Gabriel79/OmegaWithReaderTutorial) and the [tutorial](https://www.codingame.com/playgrounds/55846/reader-faire-une-application-pour-omega-sur-numworks/introduction) to code it !
+
+---
+
+# Rich text format
+Reader app supports now a rich text format :
+
+ * `$` around a LaTeX expression to render it
+ * `%` around a color-code (see below) to change the color of the text
+### LaTeX expressions
+You can read the documentation for the LaTeX Parser [here](TexParser.md).
+### Color codes :
+|code|color|
+| --:| ---:|
+|`%\last_color%`|Stop using last color|
+|`%r%`|Red|
+|`%rl%`|Light red|
+|`%m%`|Magenta|
+|`%t%`|Turquoise|
+|`%pk%`|Pink|
+|`%pp%`|Purple|
+|`%b%`|Blue|
+|`%bl%`|Light blue|
+|`%br%`|Brown|
+|`%o%`|Orange|
+|`%g%`|Green|
+|`%gl%`|Light green|
+|`%c%`|Cyan|
\ No newline at end of file
diff --git a/apps/reader/TexParser.html b/apps/reader/TexParser.html
new file mode 100644
index 00000000000..fdf7fcbac5c
--- /dev/null
+++ b/apps/reader/TexParser.html
@@ -0,0 +1,1901 @@
+
+
+
+
+ TexParser
+
+
+
+
+
+
+
+
+
+
LaTeX Parser
+
+
In the reader app, you can read a txt file. You can also read a txt file with LaTeX expression inside of it.
+
All the symbols you can use are listed here :
+
+
+
+
Command
+
Output
+
+
Command
+
Output
+
+
+
+
+
Math
+
Expressions
+
+
+
+
+
+
\frac{ab}{cd}
+
cdab
+
+
\sqrt[n]{x}
+
nx
+
+
+
Math
+
Symbols
+
+
+
+
+
+
\times
+
×
+
+
\div
+
÷
+
+
+
\forall
+
∀
+
+
\exists
+
∃
+
+
+
\partial
+
∂
+
+
\pm
+
±
+
+
+
\infty
+
∞
+
+
\approx
+
≈
+
+
+
\neq
+
=
+
+
\equiv
+
≡
+
+
+
\leq
+
≤
+
+
\geq
+
≥
+
+
+
Simple
+
Arrows
+
+
Double
+
Arrows
+
+
+
\leftarrow
+
←
+
+
\Leftarrow
+
⇐
+
+
+
\rightarrow
+
→
+
+
\Rightarrow
+
⇒
+
+
+
\uparrow
+
↑
+
+
\Uparrow
+
⇑
+
+
+
\downarrow
+
↓
+
+
\Downarrow
+
⇓
+
+
+
\leftrightarrow
+
↔
+
+
+
+
+
+
\updownarrow
+
↕
+
+
+
+
+
+
Greek Capital
+
Letters
+
+
Greek Small
+
Letters
+
+
+
\Alpha
+
A
+
+
\alpha
+
α
+
+
+
\Beta
+
B
+
+
\beta
+
β
+
+
+
\Gamma
+
Γ
+
+
\gamma
+
γ
+
+
+
\Delta
+
Δ
+
+
\delta
+
δ
+
+
+
\Epsilon
+
E
+
+
\epsilon
+
ϵ
+
+
+
\Zeta
+
Z
+
+
\zeta
+
ζ
+
+
+
\Eta
+
H
+
+
\eta
+
η
+
+
+
\Theta
+
Θ
+
+
\theta
+
θ
+
+
+
\Iota
+
I
+
+
\iota
+
ι
+
+
+
\Kappa
+
K
+
+
\kappa
+
κ
+
+
+
\Lambda
+
Λ
+
+
\lambda
+
λ
+
+
+
\Mu
+
M
+
+
\mu
+
μ
+
+
+
\Nu
+
N
+
+
\nu
+
ν
+
+
+
\Xi
+
Ξ
+
+
\xi
+
ξ
+
+
+
\Omicron
+
O
+
+
+
+
+
+
\Pi
+
Π
+
+
\pi
+
π
+
+
+
\Rho
+
P
+
+
\rho
+
ρ
+
+
+
\Sigma
+
Σ
+
+
\sigma
+
σ
+
+
+
\Tau
+
T
+
+
\tau
+
τ
+
+
+
\Upsilon
+
Υ
+
+
\upsilon
+
υ
+
+
+
\Phi
+
Φ
+
+
\phi
+
ϕ
+
+
+
\Chi
+
X
+
+
\chi
+
χ
+
+
+
\Psi
+
Ψ
+
+
\psi
+
ψ
+
+
+
\Omega
+
Ω
+
+
\omega
+
ω
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/reader/TexParser.md b/apps/reader/TexParser.md
new file mode 100644
index 00000000000..2ff9e9865ad
--- /dev/null
+++ b/apps/reader/TexParser.md
@@ -0,0 +1,51 @@
+# LaTeX Parser
+
+In the reader app, you can read a txt file. You can also read a .urt file with LaTeX expression inside of it.
+
+All the symbols you can use are listed here :
+
+|Command|Output||Command|Output|
+|--:|:--:|--:|--:|:--:|
+|Math|Expressions||||
+|`\frac{ab}{cd}`|$\frac{ab}{cd}$||`\sqrt[n]{x}`|$\sqrt[n]{x}$|
+|Math|Symbols|||
+|`\times`|$\times$||`\div`|$\div$|
+|`\forall`|$\forall$||`\exists`|$\exists$|
+|`\partial`|$\partial$||`\pm`|$\pm$|
+|`\infty`|$\infty$||`\approx`|$\approx$|
+|`\neq`|$\neq$||`\equiv`|$\equiv$|
+|`\leq`|$\leq$||`\geq`|$\geq$|
+|Simple|Arrows||Double|Arrows|
+|`\leftarrow`|$\leftarrow$||`\Leftarrow`|$\Leftarrow$|
+|`\rightarrow`|$\rightarrow$||`\Rightarrow`|$\Rightarrow$|
+|`\uparrow`|$\uparrow$||`\Uparrow`|$\Uparrow$|
+|`\downarrow`|$\downarrow$||`\Downarrow`|$\Downarrow$|
+|`\leftrightarrow`|$\leftrightarrow$||||
+|`\updownarrow`|$\updownarrow$||||
+|Greek Capital|Letters||Greek Small|Letters|
+|`\Alpha`|$\Alpha$||`\alpha`|$\alpha$|
+|`\Beta`|$\Beta$||`\beta`|$\beta$|
+|`\Gamma`|$\Gamma$||`\gamma`|$\gamma$|
+|`\Delta`|$\Delta$||`\delta`|$\delta$|
+|`\Epsilon`|$\Epsilon$||`\epsilon`|$\epsilon$|
+|`\Zeta`|$\Zeta$||`\zeta`|$\zeta$|
+|`\Eta`|$\Eta$||`\eta`|$\eta$|
+|`\Theta`|$\Theta$||`\theta`|$\theta$|
+|`\Iota`|$\Iota$||`\iota`|$\iota$|
+|`\Kappa`|$\Kappa$||`\kappa`|$\kappa$|
+|`\Lambda`|$\Lambda$||`\lambda`|$\lambda$|
+|`\Mu`|$\Mu$||`\mu`|$\mu$|
+|`\Nu`|$\Nu$||`\nu`|$\nu$|
+|`\Xi`|$\Xi$||`\xi`|$\xi$|
+|`\Omicron`|$\Omicron$|||
+|`\Pi`|$\Pi$||`\pi`|$\pi$|
+|`\Rho`|$\Rho$||`\rho`|$\rho$|
+|`\Sigma`|$\Sigma$||`\sigma`|$\sigma$|
+|`\Tau`|$\Tau$||`\tau`|$\tau$|
+|`\Upsilon`|$\Upsilon$||`\upsilon`|$\upsilon$|
+|`\Phi`|$\Phi$||`\phi`|$\phi$|
+|`\Chi`|$\Chi$||`\chi`|$\chi$|
+|`\Psi`|$\Psi$||`\psi`|$\psi$|
+|`\Omega`|$\Omega$||`\omega`|$\omega$|
+
+
diff --git a/apps/reader/app.cpp b/apps/reader/app.cpp
new file mode 100644
index 00000000000..5d9b8b1563b
--- /dev/null
+++ b/apps/reader/app.cpp
@@ -0,0 +1,40 @@
+#include "app.h"
+#include "reader_icon.h"
+#include "apps/apps_container.h"
+#include "apps/i18n.h"
+
+
+namespace Reader {
+
+I18n::Message App::Descriptor::name() {
+ return I18n::Message::ReaderApp;
+}
+
+I18n::Message App::Descriptor::upperName() {
+ return I18n::Message::ReaderAppCapital;
+}
+
+const Image * App::Descriptor::icon() {
+ return ImageStore::ReaderIcon;
+}
+
+
+App * App::Snapshot::unpack(Container * container) {
+ return new (container->currentAppBuffer()) App(this);
+}
+
+App::Descriptor * App::Snapshot::descriptor() {
+ static Descriptor descriptor;
+ return &descriptor;
+}
+
+
+App::App(Snapshot * snapshot) :
+ ::App(snapshot, &m_stackViewController),
+ m_listBookController(&m_stackViewController),
+ m_alternateEmptyViewController(&m_stackViewController, &m_listBookController, &m_listBookController),
+ m_stackViewController(&m_modalViewController, &m_alternateEmptyViewController)
+{
+}
+
+}
diff --git a/apps/reader/app.h b/apps/reader/app.h
new file mode 100644
index 00000000000..8de726e9f35
--- /dev/null
+++ b/apps/reader/app.h
@@ -0,0 +1,31 @@
+#ifndef READER_H
+#define READER_H
+
+#include
+#include "list_book_controller.h"
+
+namespace Reader {
+
+class App : public ::App {
+public:
+ class Descriptor : public ::App::Descriptor {
+ public:
+ I18n::Message name() override;
+ I18n::Message upperName() override;
+ const Image * icon() override;
+ };
+ class Snapshot : public ::App::Snapshot {
+ public:
+ App * unpack(Container * container) override;
+ Descriptor * descriptor() override;
+ };
+private:
+ App(Snapshot * snapshot);
+ ListBookController m_listBookController;
+ AlternateEmptyViewController m_alternateEmptyViewController;
+ StackViewController m_stackViewController;
+};
+
+}
+
+#endif
\ No newline at end of file
diff --git a/apps/reader/base.de.i18n b/apps/reader/base.de.i18n
new file mode 100644
index 00000000000..873f577b188
--- /dev/null
+++ b/apps/reader/base.de.i18n
@@ -0,0 +1,3 @@
+ReaderApp = "Leser"
+ReaderAppCapital = "LESER"
+NoFileToDisplay = "Keine Dateien zum Anzeigen"
diff --git a/apps/reader/base.en.i18n b/apps/reader/base.en.i18n
new file mode 100644
index 00000000000..812b213b83f
--- /dev/null
+++ b/apps/reader/base.en.i18n
@@ -0,0 +1,3 @@
+ReaderApp = "Reader"
+ReaderAppCapital = "READER"
+NoFileToDisplay = "No file to display"
diff --git a/apps/reader/base.es.i18n b/apps/reader/base.es.i18n
new file mode 100644
index 00000000000..674bec03e8b
--- /dev/null
+++ b/apps/reader/base.es.i18n
@@ -0,0 +1,3 @@
+ReaderApp = "Lector"
+ReaderAppCapital = "LECTOR"
+NoFileToDisplay ="No hay archivos para mostrar"
diff --git a/apps/reader/base.fr.i18n b/apps/reader/base.fr.i18n
new file mode 100644
index 00000000000..e017f6bda44
--- /dev/null
+++ b/apps/reader/base.fr.i18n
@@ -0,0 +1,3 @@
+ReaderApp = "Liseuse"
+ReaderAppCapital = "LISEUSE"
+NoFileToDisplay = "Aucun fichier à afficher"
diff --git a/apps/reader/base.hu.i18n b/apps/reader/base.hu.i18n
new file mode 100644
index 00000000000..d0595b0c639
--- /dev/null
+++ b/apps/reader/base.hu.i18n
@@ -0,0 +1,3 @@
+ReaderApp = "Olvasó"
+ReaderAppCapital = "OLVASÓ"
+NoFileToDisplay = "Nincs megjeleníthető fájl"
diff --git a/apps/reader/base.it.i18n b/apps/reader/base.it.i18n
new file mode 100644
index 00000000000..7adef7e4aaf
--- /dev/null
+++ b/apps/reader/base.it.i18n
@@ -0,0 +1,3 @@
+ReaderApp = "Lettore"
+ReaderAppCapital = "LETTORE"
+NoFileToDisplay = "Nessun file da visualizzare"
diff --git a/apps/reader/base.nl.i18n b/apps/reader/base.nl.i18n
new file mode 100644
index 00000000000..0e744c24cc1
--- /dev/null
+++ b/apps/reader/base.nl.i18n
@@ -0,0 +1,3 @@
+ReaderApp = "Lezer"
+ReaderAppCapital = "LEZER"
+NoFileToDisplay = "Geen bestanden om weer te geven"
diff --git a/apps/reader/base.pt.i18n b/apps/reader/base.pt.i18n
new file mode 100644
index 00000000000..0be9365227b
--- /dev/null
+++ b/apps/reader/base.pt.i18n
@@ -0,0 +1,3 @@
+ReaderApp = "Leitor"
+ReaderAppCapital = "LEITOR"
+NoFileToDisplay = "Nenhum arquivo para exibir"
diff --git a/apps/reader/list_book_controller.cpp b/apps/reader/list_book_controller.cpp
new file mode 100644
index 00000000000..8dbf7aa3b56
--- /dev/null
+++ b/apps/reader/list_book_controller.cpp
@@ -0,0 +1,106 @@
+#include "list_book_controller.h"
+#include "utility.h"
+#include
+#include "apps/i18n.h"
+
+namespace Reader
+{
+
+View* ListBookController::view() {
+ return &m_tableView;
+}
+
+ListBookController::ListBookController(Responder * parentResponder):
+ ViewController(parentResponder),
+ m_tableView(this, this, this),
+ m_readBookController(this)
+{
+ m_txtFilesNumber = filesWithExtension(".txt", m_files, k_maxFilesNumber);
+ m_urtFilesNumber = filesWithExtension(".urt", m_files + m_txtFilesNumber, k_maxFilesNumber - m_txtFilesNumber);
+ cleanRemovedBookRecord();
+}
+
+int ListBookController::numberOfRows() const {
+ return m_txtFilesNumber + m_urtFilesNumber;
+}
+
+KDCoordinate ListBookController::cellHeight() {
+ return Metric::StoreRowHeight;
+}
+
+HighlightCell * ListBookController::reusableCell(int index) {
+ return &m_cells[index];
+}
+
+int ListBookController::reusableCellCount() const {
+ return k_cellsNumber;
+}
+
+void ListBookController::willDisplayCellForIndex(HighlightCell * cell, int index) {
+ MessageTableCell<> * myTextCell = static_cast *>(cell);
+ MessageTextView* textView = static_cast(myTextCell->labelView());
+ textView->setText(m_files[index].name);
+ myTextCell->setMessageFont(KDFont::LargeFont); //TODO set cell font at building ?
+}
+
+void ListBookController::didBecomeFirstResponder() {
+ if (selectedRow() < 0) {
+ selectCellAtLocation(0, 0);
+ }
+ Container::activeApp()->setFirstResponder(&m_tableView);
+}
+
+bool ListBookController::handleEvent(Ion::Events::Event event) {
+ if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right)
+ {
+ m_readBookController.setBook(m_files[selectedRow()], selectedRow() >= m_txtFilesNumber);
+ static_cast(parentResponder())->push(&m_readBookController);
+ Container::activeApp()->setFirstResponder(&m_readBookController);
+ return true;
+ }
+
+ return false;
+}
+
+
+bool ListBookController::hasBook(const char* filename) const {
+ for(int i=0;inumberOfRecordsWithExtension("txt");
+ for(int i=0; irecordWithExtensionAtIndex("txt", i);
+ if(!hasBook(r.fullName())) {
+ r.destroy();
+ }
+ }
+
+ nb = Ion::Storage::sharedStorage()->numberOfRecordsWithExtension("urt");
+ for(int i=0; irecordWithExtensionAtIndex("urt", i);
+ if(!hasBook(r.fullName())) {
+ r.destroy();
+ }
+ }
+}
+
+bool ListBookController::isEmpty() const {
+ return m_txtFilesNumber + m_urtFilesNumber == 0;
+}
+
+I18n::Message ListBookController::emptyMessage() {
+ return I18n::Message::NoFileToDisplay;
+}
+
+Responder * ListBookController::defaultController() {
+ return parentResponder();
+}
+
+}
\ No newline at end of file
diff --git a/apps/reader/list_book_controller.h b/apps/reader/list_book_controller.h
new file mode 100644
index 00000000000..3250b173f80
--- /dev/null
+++ b/apps/reader/list_book_controller.h
@@ -0,0 +1,43 @@
+#ifndef __LIST_BOOK_CONTROLLER_H__
+#define __LIST_BOOK_CONTROLLER_H__
+
+#include
+#include
+
+#include "read_book_controller.h"
+
+namespace Reader
+{
+
+class ListBookController : public ViewController, public SimpleListViewDataSource, public SelectableTableViewDataSource, public AlternateEmptyViewDefaultDelegate
+{
+public:
+ ListBookController(Responder * parentResponder);
+ View* view() override;
+
+ int numberOfRows() const override;
+ KDCoordinate cellHeight() override;
+ HighlightCell * reusableCell(int index) override;
+ int reusableCellCount() const override;
+ void willDisplayCellForIndex(HighlightCell * cell, int index) override;
+ void didBecomeFirstResponder() override;
+ bool handleEvent(Ion::Events::Event event) override;
+ bool hasBook(const char* filename) const;
+ void cleanRemovedBookRecord();
+ bool isEmpty() const override;
+ I18n::Message emptyMessage() override;
+ Responder * defaultController() override;
+private:
+ SelectableTableView m_tableView;
+ static const int k_maxFilesNumber = 20;
+ External::Archive::File m_files[k_maxFilesNumber];
+ int m_txtFilesNumber;
+ int m_urtFilesNumber;
+ static const int k_cellsNumber = 6;
+ MessageTableCellWithChevron<> m_cells[k_cellsNumber];
+ ReadBookController m_readBookController;
+};
+
+}
+
+#endif
\ No newline at end of file
diff --git a/apps/reader/normalize.py b/apps/reader/normalize.py
new file mode 100644
index 00000000000..fff638b333f
--- /dev/null
+++ b/apps/reader/normalize.py
@@ -0,0 +1,18 @@
+import sys
+import unicodedata
+import argparse
+import io
+import shutil
+
+filename = sys.argv[1]
+
+print("Normalization of "+filename)
+
+output = open(filename+".tmp", "wb")
+
+with io.open(filename, "r", encoding='utf-8') as file:
+ for line in file:
+ unicodeLine = unicodedata.normalize("NFKD", line)
+ output.write(unicodeLine.encode("UTF-8"))
+output.close()
+shutil.move(filename+".tmp",filename)
diff --git a/apps/reader/read_book_controller.cpp b/apps/reader/read_book_controller.cpp
new file mode 100644
index 00000000000..85ef0b77c23
--- /dev/null
+++ b/apps/reader/read_book_controller.cpp
@@ -0,0 +1,72 @@
+#include "read_book_controller.h"
+#include
+
+namespace Reader
+{
+
+ReadBookController::ReadBookController(Responder * parentResponder) :
+ ViewController(parentResponder),
+ m_readerView(this)
+{
+}
+
+View * ReadBookController::view() {
+ return &m_readerView;
+}
+
+void ReadBookController::setBook(const External::Archive::File& file, bool isRichTextFile) {
+ m_file = &file;
+ loadPosition();
+ m_readerView.setText(reinterpret_cast(file.data), file.dataLength, isRichTextFile);
+}
+
+bool ReadBookController::handleEvent(Ion::Events::Event event) {
+ if(event == Ion::Events::Down) {
+ m_readerView.nextPage();
+ return true;
+ }
+ if(event == Ion::Events::Up) {
+ m_readerView.previousPage();
+ return true;
+ }
+ return false;
+}
+
+void ReadBookController::viewDidDisappear() {
+ savePosition();
+}
+
+void ReadBookController::throwError() {
+ static_cast(parentResponder())->pop();
+ Container::activeApp()->displayWarning(I18n::Message::SyntaxError);
+ // As the error is thrown when we are drawing, me must redraw the whole screen
+ AppsContainer::sharedAppsContainer()->redrawWindow();
+}
+
+void ReadBookController::savePosition() const {
+ BookSave save = m_readerView.getBookSave();
+
+ Ion::Storage::Record::ErrorStatus status = Ion::Storage::sharedStorage()->createRecordWithFullName(m_file->name, &save, sizeof(save));
+ if(Ion::Storage::Record::ErrorStatus::NameTaken == status) {
+ Ion::Storage::Record::Data data;
+ data.buffer = &save;
+ data.size = sizeof(save);
+ status = Ion::Storage::sharedStorage()->recordNamed(m_file->name).setValue(data);
+ }
+}
+
+void ReadBookController::loadPosition() {
+ Ion::Storage::Record r = Ion::Storage::sharedStorage()->recordNamed(m_file->name);
+ if(Ion::Storage::sharedStorage()->hasRecord(r)) {
+ BookSave save = *(static_cast(r.value().buffer));
+ m_readerView.setBookSave(save);
+ }
+ else {
+ m_readerView.setBookSave({
+ 0,
+ Palette::PrimaryText
+ });
+ }
+}
+
+}
\ No newline at end of file
diff --git a/apps/reader/read_book_controller.h b/apps/reader/read_book_controller.h
new file mode 100644
index 00000000000..7fb42b16587
--- /dev/null
+++ b/apps/reader/read_book_controller.h
@@ -0,0 +1,27 @@
+#ifndef _READ_BOOK_CONTROLLER_H_
+#define _READ_BOOK_CONTROLLER_H_
+
+#include
+#include "apps/external/archive.h"
+#include "word_wrap_view.h"
+
+namespace Reader {
+
+class ReadBookController : public ViewController {
+public:
+ ReadBookController(Responder * parentResponder);
+ View * view() override;
+ void setBook(const External::Archive::File& file, bool isRichTextFile);
+ bool handleEvent(Ion::Events::Event event) override;
+ void viewDidDisappear() override;
+ void savePosition() const;
+ void loadPosition();
+ void throwError();
+private:
+ WordWrapTextView m_readerView;
+ const External::Archive::File* m_file;
+};
+
+}
+
+#endif
diff --git a/apps/reader/reader_icon.png b/apps/reader/reader_icon.png
new file mode 100644
index 00000000000..78e23e13951
Binary files /dev/null and b/apps/reader/reader_icon.png differ
diff --git a/apps/reader/tex_parser.cpp b/apps/reader/tex_parser.cpp
new file mode 100644
index 00000000000..339ee8022d7
--- /dev/null
+++ b/apps/reader/tex_parser.cpp
@@ -0,0 +1,368 @@
+#include "tex_parser.h"
+#include
+
+namespace Reader {
+
+ // List of available Symbols
+ static constexpr char const * k_SymbolsCommands[] = {
+ "times", "div", "forall", "partial", "exists", "nexists", "pm", "approx", "infty", "neq", "equiv", "leq", "geq",
+ "cap", "cup", "Cap", "Cup", "subset", "nsubset", "In", "Notin",
+ "leftarrow", "uparrow", "rightarrow", "downarrow","leftrightarrow", "updownarrow", "Leftarrow", "Uparrow", "Rightarrow", "Downarrow",
+ "nwarrow", "nearrow", "swarrow", "searrow", "in", "cdot", "cdots", "ldots",
+ "Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda",
+ "Mu", "Nu", "Xi", "Omicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi","Omega",
+ "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda",
+ "mu", "nu", "xi", "omicron", "pi", "rho", "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega",
+ "sim", "f", "i",
+ };
+
+ static constexpr int const k_NumberOfSymbols = sizeof(k_SymbolsCommands) / sizeof(char *);
+
+ // List of the available Symbol's CodePoints in the same order of the Symbol's list
+ static constexpr uint32_t const k_SymbolsCodePoints[] = {
+ 0xd7, 0xf7, 0x2200, 0x2202, 0x2203, 0x2204, 0xb1, 0x2248, 0x221e, 0x2260, 0x2261, 0x2264, 0x2265,
+ 0x2229, 0x222a, 0x22c2, 0x22c3, 0x2282, 0x2284, 0x2208, 0x2209,
+ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x21d0, 0x21d1, 0x21d2, 0x21d3,
+ 0x2196, 0x2197, 0x2198, 0x2199, 0x454, 0xb7, 0x2505, 0x2026,
+ 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39a, 0x39b,
+ 0x39c, 0x39d, 0x39e, 0x39f, 0x3a0, 0x3a1, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, 0x3a8, 0x3a9,
+ 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b7, 0x3b8, 0x3b9, 0x3ba, 0x3bb,
+ 0x3bc, 0x3bd, 0x3be, 0x3bf, 0x3c0, 0x3c1, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7, 0x3c8, 0x3c9,
+ 0x7e, 0x192, 0x1d422,
+ };
+
+ static_assert(sizeof(k_SymbolsCodePoints) / sizeof(uint32_t) == k_NumberOfSymbols);
+
+ // List of available Function Commands that don't require a specific handling
+ static char const * k_FunctionCommands[] = {
+ "arccos", "arcsin", "arctan", "arg", "cos", "cosh", "cot", "coth",
+ "csc", "deg", "det", "dim", "exp", "gcd", "hom", "inf",
+ "ker", "lg", "lim", "liminf", "limsup", "ln", "log", "max",
+ "min", "Pr", "sec", "sin", "sinh", "sup", "tan", "tanh"
+ };
+
+ static int const k_NumberOfFunctionCommands = sizeof(k_FunctionCommands) / sizeof(char *);
+
+TexParser::TexParser(const char * text, const char * endOfText) :
+ m_text(text),
+ m_endOfText(endOfText),
+ m_hasError(false)
+{
+
+}
+
+Layout TexParser::getLayout() {
+ Layout layout = popText(0);
+
+ if (m_hasError) {
+ return CodePointLayout::Builder(CodePoint(0xfffd));
+ }
+
+ return layout;
+}
+
+Layout TexParser::popBlock() {
+ while (*m_text == ' ') {
+ m_text ++;
+ }
+
+ if (*m_text == '{') {
+ m_text ++;
+ return popText('}');
+ }
+
+ if (*m_text == '\\') {
+ m_text ++;
+ return popCommand();
+ }
+
+ if (m_text >= m_endOfText) {
+ m_hasError = true;
+ }
+
+ UTF8Decoder decoder(m_text);
+ m_text ++;
+ return CodePointLayout::Builder(decoder.nextCodePoint());
+}
+
+Layout TexParser::popText(char stop) {
+ HorizontalLayout layout = HorizontalLayout::Builder();
+ const char * start = m_text;
+
+ while (m_text < m_endOfText && *m_text != stop) {
+ switch (*m_text) {
+ // TODO: Factorize this code
+ case '\\':
+ if (start != m_text) {
+ layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
+ }
+ m_text ++;
+ layout.addOrMergeChildAtIndex(popCommand(), layout.numberOfChildren(), false);
+ start = m_text;
+ break;
+ case ' ':
+ if (start != m_text) {
+ layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
+ }
+ m_text ++;
+ start = m_text;
+ break;
+ case '^':
+ if (start != m_text) {
+ layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
+ }
+ m_text ++;
+ layout.addOrMergeChildAtIndex(VerticalOffsetLayout::Builder(popBlock(), VerticalOffsetLayoutNode::Position::Superscript), layout.numberOfChildren(), false);
+ start = m_text;
+ break;
+ case '_':
+ if (start != m_text) {
+ layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
+ }
+ m_text ++;
+ layout.addOrMergeChildAtIndex(VerticalOffsetLayout::Builder(popBlock(), VerticalOffsetLayoutNode::Position::Subscript), layout.numberOfChildren(), false);
+ start = m_text;
+ break;
+ default:
+ m_text ++;
+ }
+ }
+
+ if (start != m_text) {
+ layout.addOrMergeChildAtIndex(LayoutHelper::String(start, m_text - start), layout.numberOfChildren(), false);
+ }
+
+ m_text ++;
+
+ if (layout.numberOfChildren() == 1) {
+ return layout.squashUnaryHierarchyInPlace();
+ }
+
+ return layout;
+}
+
+Layout TexParser::popCommand() {
+ // TODO: Factorize this code
+ if (strncmp(k_binomCommand, m_text, strlen(k_binomCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_binomCommand)))) {
+ m_text += strlen(k_binomCommand);
+ return popBinomCommand();
+ }
+ }
+ if (strncmp(k_ceilCommand, m_text, strlen(k_ceilCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_ceilCommand)))) {
+ m_text += strlen(k_ceilCommand);
+ return popCeilCommand();
+ }
+ }
+ if (strncmp(k_integralCommand, m_text, strlen(k_integralCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_integralCommand)))) {
+ m_text += strlen(k_integralCommand);
+ return popIntegralCommand();
+ }
+ }
+ if (strncmp(k_intsetCommand, m_text, strlen(k_intsetCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_intsetCommand)))) {
+ m_text += strlen(k_intsetCommand);
+ return popIntsetCommand();
+ }
+ }
+ if (strncmp(k_floorCommand, m_text, strlen(k_floorCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_floorCommand)))) {
+ m_text += strlen(k_floorCommand);
+ return popFloorCommand();
+ }
+ }
+ if (strncmp(k_fracCommand, m_text, strlen(k_fracCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_fracCommand)))) {
+ m_text += strlen(k_fracCommand);
+ return popFracCommand();
+ }
+ }
+ if (strncmp(k_leftCommand, m_text, strlen(k_leftCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_leftCommand)))) {
+ m_text += strlen(k_leftCommand);
+ return popLeftCommand();
+ }
+ }
+ if (strncmp(k_overrightArrowCommand, m_text, strlen(k_overrightArrowCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_overrightArrowCommand)))) {
+ m_text += strlen(k_overrightArrowCommand);
+ return popOverrightarrowCommand();
+ }
+ }
+ if (strncmp(k_overlineCommand, m_text, strlen(k_overlineCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_overlineCommand)))) {
+ m_text += strlen(k_overlineCommand);
+ return popOverlineCommand();
+ }
+ }
+ if (strncmp(k_productCommand, m_text, strlen(k_productCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_productCommand)))) {
+ m_text += strlen(k_productCommand);
+ return popProductCommand();
+ }
+ }
+ if (strncmp(k_rightCommand, m_text, strlen(k_rightCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_rightCommand)))) {
+ m_text += strlen(k_rightCommand);
+ return popRightCommand();
+ }
+ }
+ if (strncmp(k_spaceCommand, m_text, strlen(k_spaceCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_spaceCommand)))) {
+ m_text += strlen(k_spaceCommand);
+ return popSpaceCommand();
+ }
+ }
+ if (strncmp(k_sqrtCommand, m_text, strlen(k_sqrtCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_sqrtCommand)))) {
+ m_text += strlen(k_sqrtCommand);
+ return popSqrtCommand();
+ }
+ }
+ if (strncmp(k_sumCommand, m_text, strlen(k_sumCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_sumCommand)))) {
+ m_text += strlen(k_sumCommand);
+ return popSumCommand();
+ }
+ }
+ if (strncmp(k_overlineCommand, m_text, strlen(k_overlineCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_overlineCommand)))) {
+ m_text += strlen(k_overlineCommand);
+ return popOverlineCommand();
+ }
+ }
+ if (strncmp(k_intsetCommand, m_text, strlen(k_intsetCommand)) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_intsetCommand)))) {
+ m_text += strlen(k_intsetCommand);
+ return popIntsetCommand();
+ }
+ }
+ for (int i = 0; i < k_NumberOfSymbols; i++) {
+ if (strncmp(k_SymbolsCommands[i], m_text, strlen(k_SymbolsCommands[i])) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_SymbolsCommands[i])))) {
+ m_text += strlen(k_SymbolsCommands[i]);
+ return popSymbolCommand(i);
+ }
+ }
+ }
+
+ for (int i = 0; i < k_NumberOfFunctionCommands; i++) {
+ if (strncmp(k_FunctionCommands[i], m_text, strlen(k_FunctionCommands[i])) == 0) {
+ if (isCommandEnded(*(m_text + strlen(k_FunctionCommands[i])))) {
+ m_text += strlen(k_FunctionCommands[i]);
+ return LayoutHelper::String(k_FunctionCommands[i], strlen(k_FunctionCommands[i]));
+ }
+ }
+ }
+
+ m_hasError = true;
+ return EmptyLayout::Builder();
+}
+
+// Expressions
+Layout TexParser::popBinomCommand() {
+ Layout numerator = popBlock();
+ Layout denominator = popBlock();
+ BinomialCoefficientLayout b = BinomialCoefficientLayout::Builder(numerator, denominator);
+ return b;
+}
+
+Layout TexParser::popCeilCommand() {
+ Layout ceil = popBlock();
+ return CeilingLayout::Builder(ceil);
+}
+
+Layout TexParser::popFloorCommand() {
+ Layout floor = popBlock();
+ return FloorLayout::Builder(floor);
+}
+
+Layout TexParser::popFracCommand() {
+ Layout numerator = popBlock();
+ Layout denominator = popBlock();
+ FractionLayout l = FractionLayout::Builder(numerator, denominator);
+ return l;
+}
+
+Layout TexParser::popIntegralCommand() {
+ Layout arg = popBlock();
+ Layout var = popBlock();
+ Layout start = popBlock();
+ Layout end = popBlock();
+ return IntegralLayout::Builder(arg, var, start, end);
+}
+
+Layout TexParser::popIntsetCommand() {
+ HorizontalLayout intset = HorizontalLayout::Builder();
+ intset.addOrMergeChildAtIndex(CodePointLayout::Builder(0x27e6), 0, false);
+ intset.addOrMergeChildAtIndex(popBlock(), intset.numberOfChildren(), false);
+ intset.addOrMergeChildAtIndex(CodePointLayout::Builder(0x27e7), intset.numberOfChildren(), false);
+ return intset;
+}
+
+Layout TexParser::popLeftCommand() {
+ m_text++;
+ return LeftParenthesisLayout::Builder();
+}
+
+Layout TexParser::popProductCommand() {
+ Layout arg = popBlock();
+ Layout var = popBlock();
+ Layout start = popBlock();
+ Layout end = popBlock();
+ return ProductLayout::Builder(arg, var, start, end);
+}
+
+
+Layout TexParser::popRightCommand() {
+ m_text++;
+ return RightParenthesisLayout::Builder();
+}
+
+Layout TexParser::popSqrtCommand() {
+ while (*m_text == ' ') {
+ m_text ++;
+ }
+ if (*m_text == '[') {
+ m_text ++;
+ Layout rootFactor = popText(']');
+ Layout belowRoot = popBlock();
+ return NthRootLayout::Builder(belowRoot, rootFactor);
+ }
+ else {
+ return NthRootLayout::Builder(popBlock());
+ }
+}
+
+Layout TexParser::popSumCommand() {
+ Layout arg = popBlock();
+ Layout var = popBlock();
+ Layout start = popBlock();
+ Layout end = popBlock();
+ return SumLayout::Builder(arg, var, start, end);
+}
+
+Layout TexParser::popSpaceCommand() {
+ return LayoutHelper::String(" ", 1);
+}
+
+Layout TexParser::popOverrightarrowCommand() {
+ return VectorLayout::Builder(popBlock());
+}
+
+Layout TexParser::popOverlineCommand() {
+ return ConjugateLayout::Builder(popBlock());
+}
+
+Layout TexParser::popSymbolCommand(int SymbolIndex) {
+ uint32_t codePoint = k_SymbolsCodePoints[SymbolIndex];
+ return CodePointLayout::Builder(codePoint);
+}
+
+inline bool TexParser::isCommandEnded(char c) const {
+ return !(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z');
+}
+
+}
diff --git a/apps/reader/tex_parser.h b/apps/reader/tex_parser.h
new file mode 100644
index 00000000000..65cb0cc6ab8
--- /dev/null
+++ b/apps/reader/tex_parser.h
@@ -0,0 +1,66 @@
+#ifndef __TEX_PARSER_H__
+#define __TEX_PARSER_H__
+
+#include
+#include
+#include
+
+using namespace Poincare;
+
+namespace Reader
+{
+/// @brief Class used in the WordWrapTextView class to parse a Tex expression
+class TexParser {
+public:
+ TexParser(const char * text, const char * endOfText);
+ Layout getLayout();
+private:
+ Layout popBlock();
+ Layout popText(char stop);
+ Layout popCommand();
+
+ // Expressions
+ Layout popBinomCommand();
+ Layout popCeilCommand();
+ Layout popFloorCommand();
+ Layout popFracCommand();
+ Layout popIntegralCommand();
+ Layout popIntsetCommand();
+ Layout popLeftCommand();
+ Layout popOverrightarrowCommand();
+ Layout popOverlineCommand();
+ Layout popProductCommand();
+ Layout popRightCommand();
+ Layout popSqrtCommand();
+ Layout popSumCommand();
+ Layout popSpaceCommand();
+
+ //Symbols
+ Layout popSymbolCommand(int SymbolIndex);
+
+ const char * m_text;
+ const char * m_endOfText;
+ bool m_hasError;
+
+ inline bool isCommandEnded(char c) const;
+
+ // Expressions that require specific handling
+ static constexpr char const * k_binomCommand = "binom";
+ static constexpr char const * k_ceilCommand = "ceil";
+ static constexpr char const * k_floorCommand = "floor";
+ static constexpr char const * k_fracCommand = "frac";
+ static constexpr char const * k_integralCommand = "int";
+ static constexpr char const * k_intsetCommand = "intset";
+ static constexpr char const * k_leftCommand = "left";
+ static constexpr char const * k_overrightArrowCommand = "overrightarrow";
+ static constexpr char const * k_overlineCommand = "overline";
+ static constexpr char const * k_productCommand = "prod";
+ static constexpr char const * k_rightCommand = "right";
+ static constexpr char const * k_spaceCommand = "space";
+ static constexpr char const * k_sqrtCommand = "sqrt";
+ static constexpr char const * k_sumCommand = "sum";
+};
+
+}
+
+#endif
diff --git a/apps/reader/utility.cpp b/apps/reader/utility.cpp
new file mode 100644
index 00000000000..c29c28f1f29
--- /dev/null
+++ b/apps/reader/utility.cpp
@@ -0,0 +1,152 @@
+#include "utility.h"
+
+#include
+
+#ifndef DEVICE
+#include
+#include
+#include
+#endif
+
+namespace Reader
+{
+
+bool stringEndsWith(const char* str, const char* pattern) {
+ int strLength = strlen(str);
+ int patternLength = strlen(pattern);
+ if (patternLength > strLength) {
+ return false;
+ }
+
+ const char* strIter = str + strlen(str);
+ const char* patternIter = pattern + strlen(pattern);
+
+ while(*strIter == *patternIter) {
+ if(patternIter == pattern) {
+ return true;
+ }
+ strIter--;
+ patternIter--;
+ }
+ return false;
+}
+
+void stringNCopy(char* dest, int max, const char* src, int len) {
+ while(len>0 && max >1 && *src)
+ {
+ *dest = *src;
+ dest++;
+ src++;
+ len--;
+ max--;
+ }
+ *dest=0;
+}
+
+
+#ifdef DEVICE
+
+int filesWithExtension(const char* extension, External::Archive::File* files, int filesSize) {
+ size_t nbTotalFiles = External::Archive::numberOfFiles();
+ int nbFiles = 0;
+ for(size_t i=0; i < nbTotalFiles; ++i) {
+ External::Archive::File file;
+ External::Archive::fileAtIndex(i, file);
+ if(stringEndsWith(file.name, extension)) {
+ files[nbFiles] = file;
+ nbFiles++;
+ if(nbFiles == filesSize)
+ break;
+ }
+ }
+ return nbFiles;
+}
+#else
+
+static void fillFileData(External::Archive::File& file) {
+ file.data = nullptr;
+ file.dataLength = 0;
+
+ struct stat info;
+ if (stat(file.name, &info) != 0) {
+ return;
+ }
+
+ unsigned char* content = new unsigned char[info.st_size];
+ if (content == NULL) {
+ return;
+ }
+ FILE *fp = fopen(file.name, "rb");
+ if (fp == NULL) {
+ return ;
+ }
+
+ fread(content, info.st_size, 1, fp);
+ fclose(fp);
+ file.data = content;
+ file.dataLength = info.st_size;
+}
+
+int filesWithExtension(const char* extension, External::Archive::File* files, int filesSize) {
+ dirent *file;
+ DIR *d = opendir(".");
+ int nb = 0;
+ if (d) {
+ while ((file = readdir(d)) != NULL) {
+ if(stringEndsWith(file->d_name, extension)) {
+ files[nb].name = strdup(file->d_name);//will probably leak
+ fillFileData(files[nb]);
+ nb++;
+ if(nb == filesSize) {
+ break;
+ }
+ }
+ }
+ closedir(d);
+ }
+ return nb;
+}
+#endif
+
+const char * EndOfPrintableWord(const char * word, const char * end) {
+ if (word >= end) {
+ return word;
+ }
+ UTF8Decoder decoder(word);
+ CodePoint codePoint = decoder.nextCodePoint();
+ const char * result = word;
+ while (codePoint != '\n' && codePoint != ' ' && codePoint != '%' && codePoint != '$' && codePoint != '\\') {
+ result = decoder.stringPosition();
+ if (result >= end) {
+ break;
+ }
+ codePoint = decoder.nextCodePoint();
+ }
+ return result;
+}
+
+const char * StartOfPrintableWord(const char * word, const char * start) {
+ if (word <= start) {
+ return word;
+ }
+ // Go to start of code point with some code points dark magic
+ if (!((*word & 0x80) == 0)) {
+ word--;
+ while (!(*word & 0x80 && *word & 0x40)) {
+ word--;
+ }
+ }
+ UTF8Decoder decoder(start, word);
+ CodePoint codePoint = decoder.previousCodePoint();
+ const char * result = word;
+ while (codePoint != '\n' && codePoint != ' ' && codePoint != '%' && codePoint != '$') {
+ result = decoder.stringPosition();
+ if (result <= start) {
+ break;
+ }
+ codePoint = decoder.previousCodePoint();
+ }
+ return result;
+}
+
+}
\ No newline at end of file
diff --git a/apps/reader/utility.h b/apps/reader/utility.h
new file mode 100644
index 00000000000..61aabbf2cf6
--- /dev/null
+++ b/apps/reader/utility.h
@@ -0,0 +1,18 @@
+#ifndef __UTILITY_H__
+#define __UTILITY_H__
+
+#include
+#include
+#include
+
+namespace Reader
+{
+
+bool stringEndsWith(const char* str, const char* end);
+int filesWithExtension(const char* extension, External::Archive::File* files, int filesSize);
+void stringNCopy(char* dest, int max, const char* src, int len);
+const char * EndOfPrintableWord(const char * word, const char * end);
+const char * StartOfPrintableWord(const char * word, const char * start);
+
+}
+#endif
\ No newline at end of file
diff --git a/apps/reader/word_wrap_view.cpp b/apps/reader/word_wrap_view.cpp
new file mode 100644
index 00000000000..3585e966951
--- /dev/null
+++ b/apps/reader/word_wrap_view.cpp
@@ -0,0 +1,789 @@
+
+#include "word_wrap_view.h"
+#include "utility.h"
+#include "tex_parser.h"
+#include
+#include "../shared/poincare_helpers.h"
+#include
+#include "read_book_controller.h"
+
+namespace Reader
+{
+
+WordWrapTextView::WordWrapTextView(ReadBookController * readBookController) :
+ PointerTextView(GlobalPreferences::sharedGlobalPreferences()->font()),
+ m_pageOffset(0),
+ m_nextPageOffset(0),
+ m_length(0),
+ m_isRichTextFile(false), // Value isn't important, it will change when the file is loaded
+ m_lastPagesOffsetsIndex(0),
+ m_textColor(Palette::PrimaryText),
+ m_readBookController(readBookController)
+{
+ for (int i = 0; i < k_lastOffsetsBufferSize; i++) {
+ m_lastPagesOffsets[i] = -1; // -1 Means : no informations
+ }
+}
+
+void WordWrapTextView::nextPage() {
+ if(m_nextPageOffset >= m_length) {
+ return;
+ }
+ m_lastPagesOffsets[m_lastPagesOffsetsIndex] = m_pageOffset;
+ m_lastPagesOffsetsIndex = (m_lastPagesOffsetsIndex + 1) % k_lastOffsetsBufferSize;
+ m_pageOffset = m_nextPageOffset;
+ markRectAsDirty(bounds());
+}
+
+void WordWrapTextView::setText(const char* text, int length, bool isRichTextFile) {
+ PointerTextView::setText(text);
+ m_length = length;
+ m_isRichTextFile = isRichTextFile;
+}
+
+void WordWrapTextView::previousPage() {
+ if(m_pageOffset <= 0) {
+ return;
+ }
+
+ /* We check if we have available data in our buffer */
+ int offsetToCheck = (m_lastPagesOffsetsIndex + k_lastOffsetsBufferSize - 1) % k_lastOffsetsBufferSize;
+ if (m_lastPagesOffsets[offsetToCheck] != -1) {
+ m_lastPagesOffsetsIndex = offsetToCheck;
+ m_pageOffset = m_lastPagesOffsets[offsetToCheck];
+ m_lastPagesOffsets[offsetToCheck] = -1;
+ } else if (m_isRichTextFile) {
+ richTextPreviousPage();
+ } else {
+ plainTextPreviousPage();
+ }
+
+ markRectAsDirty(bounds());
+}
+
+void WordWrapTextView::richTextPreviousPage() {
+ const int charWidth = m_font->glyphSize().width();
+ const int charHeight = m_font->glyphSize().height();
+
+ const char * endOfWord = text() + m_pageOffset - 1;
+ if (*endOfWord == '\n') {
+ endOfWord --;
+ }
+
+ KDCoordinate baseline = charHeight / 2;
+
+ KDPoint textBottomEndPosition = KDPoint(m_frame.width() - k_margin, m_frame.height() - k_margin);
+ KDCoordinate lineHeight = charHeight;
+
+ while(endOfWord >= text()) {
+ // 1. Skip whitespaces and line jumps
+ const char * invisiblesCharJumped = endOfWord; // We use this to update endOfWord only if we don't change page
+ bool changePage = false;
+ while(invisiblesCharJumped >= text() && (*invisiblesCharJumped == ' ' || *invisiblesCharJumped == '\n')) {
+ if(*invisiblesCharJumped == '\n') {
+ textBottomEndPosition = KDPoint(m_frame.width() - k_margin, textBottomEndPosition.y() - lineHeight);
+ lineHeight = charHeight;
+ baseline = charHeight / 2;
+ // We check if we must change page
+ if (textBottomEndPosition.y() - lineHeight <= k_margin) {
+ // We don't let text on a new line or a space
+ endOfWord ++;
+ changePage = true;
+ break;
+ }
+ } else {
+ textBottomEndPosition = KDPoint(textBottomEndPosition.x() - charWidth, textBottomEndPosition.y());
+ }
+ invisiblesCharJumped--;
+ }
+
+ if (changePage) {
+ break;
+ }
+ endOfWord = invisiblesCharJumped;
+
+ // 3. If word is a color change
+ if (*endOfWord == '%' && *(endOfWord - 1) != '\\') {
+ const char * startOfWord = endOfWord - 2;
+ while (*startOfWord != '%') {
+ startOfWord--;
+ }
+
+ if (updateTextColorBackward(startOfWord)) {
+ endOfWord = startOfWord - 1; // Update next endOfWord
+ continue;
+ } else {
+ m_readBookController->throwError();
+ return;
+ }
+ }
+
+ KDSize textSize = KDSizeZero;
+
+ // 4. If word is a mathematical expression
+ if (*endOfWord == '$' && *(endOfWord - 1) != '\\') {
+ // We go to the end of the expression + 1
+ const char * expressionStart = --endOfWord;
+ while (*expressionStart != '$') {
+ if (expressionStart < text()) {
+ break; // File isn't rightly formated
+ }
+ expressionStart --;
+ }
+
+ TexParser parser = TexParser(expressionStart, endOfWord);
+ Layout layout = parser.getLayout();
+
+ KDCoordinate layoutBaseline = layout.baseline();
+
+ // We check if we must change baseline
+ if (layoutBaseline > baseline) {
+ baseline = layoutBaseline;
+ }
+
+ KDSize layoutSize = layout.layoutSize();
+ textSize = KDSize(layoutSize.width(), layoutSize.height() + baseline - layoutBaseline);
+
+ endOfWord = expressionStart;
+ }
+
+ // 5. Else it's text
+ else {
+ // We go to the start of the word
+ const char * startOfWord = StartOfPrintableWord(endOfWord, text());
+
+ textSize = m_font->stringSizeUntil(startOfWord, endOfWord + 1);
+
+ endOfWord = startOfWord;
+ }
+
+ // 6. We check if we must change line
+ if (textBottomEndPosition.x() - textSize.width() <= k_margin) {
+ textBottomEndPosition = KDPoint(m_frame.width() - k_margin, textBottomEndPosition.y() - lineHeight);
+ lineHeight = 0;
+ baseline = charHeight;
+ // We will check if we must change page below
+ }
+ textBottomEndPosition = KDPoint(textBottomEndPosition.x() - textSize.width(), textBottomEndPosition.y());
+
+ // 7. We update height of the line if needed
+ if (textSize.height() > lineHeight) {
+ lineHeight = textSize.height();
+ // We check if we must change page
+ if (textBottomEndPosition.y() - lineHeight <= k_margin) {
+ break;
+ }
+ }
+
+ endOfWord -= 1;
+ }
+
+ if (endOfWord + 1 == text()) {
+ m_pageOffset = 0;
+ } else {
+ m_pageOffset = endOfWord - text();
+ }
+}
+
+void WordWrapTextView::plainTextPreviousPage() {
+ const int charWidth = m_font->glyphSize().width();
+ const int charHeight = m_font->glyphSize().height();
+
+ const char * endOfWord = text() + m_pageOffset - 1;
+ const char * startOfWord = UTF8Helper::BeginningOfWord(text(), endOfWord);
+
+ KDPoint textEndPosition(m_frame.width() - k_margin, m_frame.height() - k_margin);
+
+ while(endOfWord>text()) {
+ KDSize textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
+ KDPoint textStartPosition = KDPoint(textEndPosition.x()-textSize.width(), textEndPosition.y());
+
+ if (textStartPosition.x() < k_margin) {
+ // We check if the word is too long to be displayed entirely on just one line
+ if(textSize.width() > m_frame.width() - 2 * k_margin) {
+ startOfWord = endOfWord - (textEndPosition.x() - k_margin) / charWidth;
+ continue;
+ }
+ textEndPosition = KDPoint(m_frame.width() - k_margin, textEndPosition.y() - charHeight);
+ textStartPosition = KDPoint(textEndPosition.x() - textSize.width(), textEndPosition.y());
+ }
+ if (textEndPosition.y() - textSize.height() < k_margin) {
+ break;
+ }
+
+ --startOfWord;
+ while (startOfWord >= text() && (*startOfWord == ' ' || *startOfWord == '\n')) {
+ if (*startOfWord == ' ') {
+ textStartPosition = KDPoint(textStartPosition.x() - charWidth, textStartPosition.y());
+ } else {
+ textStartPosition = KDPoint(m_frame.width() - k_margin, textStartPosition.y() - charHeight);
+ }
+ --startOfWord;
+ }
+
+ if (textStartPosition.y() < k_margin) { // If out of page, quit
+ break;
+ }
+
+ if (textStartPosition.y() != textEndPosition.y()) { // If line changed, x is at start of line
+ textStartPosition = KDPoint(m_frame.width() - k_margin, textStartPosition.y());
+ }
+ if (textStartPosition.x() <= k_margin) { // Go to line if left overflow
+ textStartPosition = KDPoint(m_frame.width() - k_margin, textStartPosition.y() - charHeight);
+ }
+
+ textEndPosition = textStartPosition;
+ endOfWord = startOfWord + 1;
+ startOfWord = UTF8Helper::BeginningOfWord(text(), endOfWord);
+ }
+
+ while (endOfWord < text() + m_length && (*endOfWord == ' ' || *endOfWord == '\n')) {
+ endOfWord++;
+ }
+
+ m_pageOffset = endOfWord - text();
+}
+
+void WordWrapTextView::drawRect(KDContext * ctx, KDRect rect) const {
+ ctx->fillRect(KDRect(0, 0, bounds().width(), bounds().height()), m_backgroundColor);
+
+ if (m_isRichTextFile) {
+ richTextDrawRect(ctx, rect);
+ } else {
+ plainTextDrawRect(ctx, rect);
+ }
+}
+
+void WordWrapTextView::richTextDrawRect(KDContext * ctx, KDRect rect) const {
+ enum class ToDraw {
+ Text,
+ Expression
+ };
+
+ bool endOfPage = false;
+
+ const char * endOfFile = text() + m_length;
+ const char * startOfWord = text() + m_pageOffset;
+
+ const int charWidth = m_font->glyphSize().width();
+ const int charHeight = m_font->glyphSize().height();
+
+ const int wordMaxLength = (m_frame.width() - 2*k_margin ) / charWidth;
+ char word[wordMaxLength];
+
+ Layout tooBigLayout = EmptyLayout::Builder(); // To store layouts that are too big to be displayed entirely on one line
+ KDCoordinate tooBigLayoutAlreadyWroteWidth = 0; // We store here the part of the layout that has already been written
+
+ KDPoint textPosition = KDPoint(k_margin, k_margin);
+
+ while (!endOfPage && (startOfWord < endOfFile || !tooBigLayout.isEmpty())) {
+ // We process line by line
+
+ const char * firstReadIndex = startOfWord;
+
+ // 1. We compute the size of what we are going to draw and the baseline
+ KDSize lineSize = KDSize(0, charHeight);
+ KDCoordinate baseline = charHeight / 2;
+
+ while (firstReadIndex < endOfFile) {
+ // 1.0. We check if we are drawing a too big layout
+ if (!tooBigLayout.isEmpty()) {
+ lineSize = tooBigLayout.layoutSize();
+ baseline = tooBigLayout.baseline();
+
+ if (tooBigLayout.layoutSize().width() - tooBigLayoutAlreadyWroteWidth > m_frame.width() - 2 * k_margin) {
+ // Remaining part of the layout don't fit on the line
+ break;
+ }
+ }
+
+ KDSize textSize = KDSizeZero;
+ KDCoordinate updatedBaseline = 0; // 0 if it's not a layout
+
+ // 1.1. And we check if we are at the end of the line
+ if(*firstReadIndex == '\n') {
+ break;
+ }
+
+ // 1.2. Check if we are in a color change
+ if (*firstReadIndex == '%') { // We assume each '%' non-escaped is announcing a color change
+ // We go to the end of the color change + 1
+ const char * startIndex = firstReadIndex;
+
+ do {
+ firstReadIndex ++;
+ } while (*firstReadIndex != '%' && firstReadIndex < endOfFile && startIndex - firstReadIndex < 5);
+ firstReadIndex ++;
+
+ if (firstReadIndex - startIndex > 5) {
+ m_readBookController->throwError();
+ return;
+ }
+
+ continue;
+ }
+
+ // 1.3. Check if we are in a math expression
+ if (*firstReadIndex == '$') {
+ // We go to the end of the expression + 1
+ const char * expressionStart = ++firstReadIndex;
+ while (*firstReadIndex != '$') {
+ if (firstReadIndex > endOfFile) {
+ break; // File isn't rightly formated
+ }
+ firstReadIndex ++;
+ }
+
+ TexParser parser = TexParser(expressionStart, firstReadIndex);
+ Layout firstReadLayout = parser.getLayout();
+
+ KDCoordinate layoutBaseline = firstReadLayout.baseline();
+
+ updatedBaseline = baseline; // We really update baseline after, if the layout fit on the line
+ if (layoutBaseline > baseline) {
+ updatedBaseline = layoutBaseline;
+ }
+
+ KDSize layoutSize = firstReadLayout.layoutSize();
+ textSize = KDSize(layoutSize.width(), layoutSize.height() + updatedBaseline - layoutBaseline);
+
+ firstReadIndex ++;
+ }
+
+ // 1.4. Else it's text
+ else {
+ if ((*firstReadIndex == '\\' && *(firstReadIndex + 1) == '$') || (*firstReadIndex == '\\' && *(firstReadIndex + 1) == '%')) { // We escape '$' and '%' if needed
+ firstReadIndex ++;
+ }
+
+ const char * endOfWord = EndOfPrintableWord(firstReadIndex + 1, endOfFile);
+
+ textSize = m_font->stringSizeUntil(firstReadIndex, endOfWord);
+
+ firstReadIndex = endOfWord;
+ }
+
+ // 1.5. We update size
+ int newWidth = lineSize.width() + textSize.width();
+ // We check if the new text fit on the line.
+ // If not, we look if only the word cannot fit on one line. If so, we do not go to the line
+ if (newWidth > m_frame.width() - 2 * k_margin && !(textSize.width() > m_frame.width() - 2 * k_margin)) {
+ break;
+ }
+
+ if (updatedBaseline) { // Now we update baseline
+ baseline = updatedBaseline;
+ }
+
+ int newHeight;
+ if (lineSize.height() > textSize.height()) {
+ newHeight = lineSize.height();
+ } else {
+ newHeight = textSize.height();
+ // We check if all the content can be displayed
+ if (textPosition.y() + newHeight > bounds().height() - k_margin) {
+ endOfPage = true;
+ break;
+ }
+ }
+ lineSize = KDSize(lineSize.width() + textSize.width(), newHeight);
+
+ // 1.6. We go to the next word
+ while (*firstReadIndex == ' ') {
+ lineSize = KDSize(lineSize.width() + charWidth, lineSize.height());
+ ++firstReadIndex;
+ }
+ }
+
+ if (endOfPage) {
+ break;
+ }
+
+ // 2. And now... we read the line again to draw it !
+ while (startOfWord < endOfFile || !tooBigLayout.isEmpty()) {
+ // 2.0 Before all, we check if we were drawing a layout that was too big to fit on one line.
+ // In this case, we do all the routine here.
+ if (!tooBigLayout.isEmpty()) {
+ KDPoint position = KDPoint(textPosition.x() - tooBigLayoutAlreadyWroteWidth, textPosition.y());
+ tooBigLayout.draw(ctx, position, m_textColor, m_backgroundColor);
+ // We fill the left margin
+ ctx->fillRect(KDRect(0, textPosition.y(), k_margin, tooBigLayout.layoutSize().height()), m_backgroundColor);
+
+ KDCoordinate drawnWidth = tooBigLayout.layoutSize().width() - tooBigLayoutAlreadyWroteWidth;
+ tooBigLayoutAlreadyWroteWidth += drawnWidth;
+
+ if (drawnWidth > m_frame.width() - 2 * k_margin) {
+ // We have to fill the margin with the background color
+ ctx->fillRect(KDRect(textPosition.x() + drawnWidth, textPosition.y(), k_margin, lineSize.height()), m_backgroundColor);
+ textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
+ break;
+ } else {
+ tooBigLayout = EmptyLayout::Builder(); // We have finished drawing the tooBigLayout
+ }
+ continue;
+ }
+
+ Layout layout;
+
+ //2.1. We check if we are at the end of the line
+ if (*startOfWord == '\n') {
+ startOfWord++;
+ textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
+ break;
+ // We aren't supposed to be at the end of the page, else the loop on top would have stopped drawing
+ }
+
+ const char * endOfWord;
+
+ // 2.2. Check if we are in a color change
+ if (*startOfWord == '%') {
+ if (updateTextColorForward(startOfWord)) {
+ startOfWord += 2; // We can add at least 2 ('%' + the color first char)
+ while (*startOfWord != '%') {
+ startOfWord ++;
+ }
+ startOfWord ++;
+ continue;
+ }
+ else {
+ m_readBookController->throwError();
+ return;
+ }
+ }
+
+ // 2.3. Check what we are going to draw and his size
+
+ KDSize textSize = KDSizeZero;
+ ToDraw toDraw;
+
+ // 2.3.1. Check if we are in a math expression
+ if (*startOfWord == '$') {
+ endOfWord = startOfWord + 1;
+ while (*endOfWord != '$') {
+ if (endOfWord > endOfFile) {
+ break; // File isn't rightly formated
+ }
+ endOfWord ++;
+ }
+ endOfWord ++;
+
+ TexParser parser = TexParser(startOfWord + 1, endOfWord - 1);
+ layout = parser.getLayout();
+ textSize = layout.layoutSize();
+
+ toDraw = ToDraw::Expression;
+ }
+
+ // 2.3.2 Else it's text
+ else {
+ if ((*startOfWord == '\\' && *(startOfWord + 1) == '$') || (*startOfWord == '\\' && *(startOfWord + 1) == '%')) {
+ startOfWord ++;
+ }
+ endOfWord = EndOfPrintableWord(startOfWord + 1, endOfFile);
+ textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
+ stringNCopy(word, wordMaxLength, startOfWord, endOfWord-startOfWord);
+ toDraw = ToDraw::Text;
+ }
+
+ // 2.4 We decide where to draw and if we must change line
+ KDPoint endTextPosition = KDPoint(textPosition.x() + textSize.width(), textPosition.y());
+
+ // 2.4.1. Check if we need to go to the next line
+ if(endTextPosition.x() > m_frame.width() - k_margin) {
+
+ // We check if the word is too long to be displayed entirely on just one line
+ if(textSize.width() > m_frame.width() - 2 * k_margin) {
+ if (toDraw == ToDraw::Text) {
+ startOfWord = endOfWord - (endTextPosition.x() - k_margin) / charWidth;
+ continue;
+ } else {
+ assert(toDraw == ToDraw::Expression);
+ tooBigLayout = layout;
+ tooBigLayoutAlreadyWroteWidth += m_frame.width() - k_margin - textPosition.x();
+ endTextPosition = KDPoint(k_margin, textPosition.y() + lineSize.height()); // We jump line now, because this will be the next value of textPosition
+ }
+ } else {
+ textPosition = KDPoint(k_margin, textPosition.y() + lineSize.height());
+ // endTextPosition will be updated later
+ break;
+ }
+ }
+
+ // 2.5. Now we draw !
+ if (toDraw == ToDraw::Expression) {
+ KDPoint position = KDPoint(textPosition.x(), textPosition.y() + baseline - layout.baseline());
+ layout.draw(ctx, position, m_textColor, m_backgroundColor);
+
+ if (!tooBigLayout.isEmpty()) {
+ // We fill the margin
+ ctx->fillRect(KDRect(m_frame.width() - k_margin, textPosition.y(), k_margin, lineSize.height()), m_backgroundColor);
+ }
+ }
+ else {
+ KDPoint position = KDPoint(textPosition.x(), textPosition.y() + baseline - charHeight / 2);
+ ctx->drawString(word, position, m_font, m_textColor, m_backgroundColor);
+ }
+
+ // 2.6. Update the position
+ textPosition = endTextPosition;
+
+ // 2.7. And we go to the next word
+ while (*endOfWord == ' ') {
+ endOfWord++;
+ textPosition = KDPoint(textPosition.x() + charWidth, textPosition.y());
+ }
+ startOfWord = endOfWord;
+
+ // 2.8. We exit now if we are in the "too big layout" case
+ if (!tooBigLayout.isEmpty()) {
+ break;
+ }
+ }
+ }
+ m_nextPageOffset = startOfWord - text();
+}
+
+
+void WordWrapTextView::plainTextDrawRect(KDContext * ctx, KDRect rect) const {
+ ctx->fillRect(KDRect(0, 0, bounds().width(), bounds().height()), m_backgroundColor);
+
+ const char * endOfFile = text() + m_length;
+ const char * startOfWord = text() + m_pageOffset;
+ const char * endOfWord = UTF8Helper::EndOfWord(startOfWord, endOfFile);
+ KDPoint textPosition(k_margin, k_margin);
+
+ const int wordMaxLength = 128;
+ char word[wordMaxLength];
+
+ const int charWidth = m_font->glyphSize().width();
+ const int charHeight = m_font->glyphSize().height();
+
+ while(startOfWord < endOfFile) {
+ KDSize textSize = m_font->stringSizeUntil(startOfWord, endOfWord);
+ KDPoint nextTextPosition = KDPoint(textPosition.x()+textSize.width(), textPosition.y());
+
+ if(nextTextPosition.x() > m_frame.width() - k_margin) { // Right overflow
+ // We check if the word is too long to be displayed entirely on just one line
+ if(textSize.width() > m_frame.width() - 2 * k_margin) {
+ endOfWord = startOfWord + (m_frame.width() - k_margin - textPosition.x()) / charWidth;
+ continue;
+ }
+ textPosition = KDPoint(k_margin, textPosition.y() + textSize.height());
+ nextTextPosition = KDPoint(k_margin + textSize.width(), textPosition.y());
+ }
+
+ if(textPosition.y() + textSize.height() > m_frame.height() - k_margin) { // Bottom overflow
+ break;
+ }
+
+ stringNCopy(word, wordMaxLength, startOfWord, endOfWord-startOfWord);
+ ctx->drawString(word, textPosition, m_font, m_textColor, m_backgroundColor);
+
+ while(*endOfWord == ' ' || *endOfWord == '\n') {
+ if(*endOfWord == ' ') {
+ nextTextPosition = KDPoint(nextTextPosition.x() + charWidth, nextTextPosition.y());
+ }
+ else {
+ nextTextPosition = KDPoint(k_margin, nextTextPosition.y() + charHeight);
+ }
+ ++endOfWord;
+ }
+
+ //We must change value of startOfWord now to avoid having
+ //two times the same word if the break below is used
+ startOfWord = endOfWord;
+
+ if(nextTextPosition.y() + textSize.height() > m_frame.height() - k_margin) { // If out of page, quit
+ break;
+ }
+ if(nextTextPosition.y() != textPosition.y()) { // If line changed, x is at start of line
+ nextTextPosition = KDPoint(k_margin, nextTextPosition.y());
+ }
+ if(nextTextPosition.x() >= m_frame.width() - k_margin) { // Go to line if right overflow
+ nextTextPosition = KDPoint(k_margin, nextTextPosition.y() + textSize.height());
+ }
+
+ textPosition = nextTextPosition;
+ endOfWord = UTF8Helper::EndOfWord(startOfWord, endOfFile);
+ }
+
+ m_nextPageOffset = startOfWord - text();
+}
+
+BookSave WordWrapTextView::getBookSave() const {
+ return {
+ m_pageOffset,
+ m_textColor
+ };
+}
+
+void WordWrapTextView::setBookSave(BookSave save) {
+ m_pageOffset = save.offset;
+ // TODO: Understand why the color save crash the calculator and fix it
+ // m_textColor = save.color;
+ m_lastPagesOffsetsIndex = 0;
+
+ for (int i = 0; i < k_lastOffsetsBufferSize; i++) {
+ m_lastPagesOffsets[i] = -1; // -1 Means : no informations
+ }
+}
+
+bool WordWrapTextView::updateTextColorForward(const char * colorStart) const {
+
+ if (*(colorStart + 1) == '\\' && (*(colorStart + 3) == '%' || *(colorStart + 4) == '%')) {
+ m_textColor = Palette::PrimaryText;
+ return true;
+ }
+
+ int keySize = 1;
+ KDColor lastColor = m_textColor;
+
+ switch (*(colorStart+1))
+ {
+ case 'r':
+ if (*(colorStart+2) == 'l') {
+ m_textColor = Palette::RedLight;
+ keySize = 2;
+ }
+ else {
+ m_textColor = Palette::Red;
+ }
+ break;
+ case 'm':
+ m_textColor = Palette::Magenta;
+ break;
+ case 't':
+ m_textColor = Palette::Turquoise;
+ break;
+ case 'p':
+ if (*(colorStart+2) == 'k') {
+ m_textColor = Palette::Pink;
+ keySize = 2;
+ }
+ else if (*(colorStart+2) == 'p') {
+ m_textColor = Palette::Purple;
+ keySize = 2;
+ }
+ break;
+ case 'b':
+ if (*(colorStart+2) == 'r') {
+ m_textColor = Palette::Brown;
+ keySize = 2;
+ }
+ else if (*(colorStart+2) == 'l') {
+ m_textColor = Palette::BlueLight;
+ keySize = 2;
+ }
+ else {
+ m_textColor = Palette::Blue;
+ }
+ break;
+ case 'o':
+ m_textColor = Palette::Orange;
+ break;
+ case 'g':
+ if (*(colorStart+2) == 'l') {
+ m_textColor = Palette::GreenLight;
+ keySize = 2;
+ }
+ else {
+ m_textColor = Palette::Green;
+ }
+ break;
+ case 'c':
+ m_textColor = Palette::Cyan;
+ break;
+
+ default:
+ return false;
+ }
+
+ if (*(colorStart + keySize + 1) != '%') {
+ m_textColor = lastColor;
+ return false;
+ }
+
+ return true;
+}
+
+bool WordWrapTextView::updateTextColorBackward(const char * colorStart) const {
+
+ if (*(++colorStart) != '\\') {
+ if (*(colorStart + 1) == '%' || *(colorStart + 2) == '%') {
+ m_textColor = Palette::PrimaryText;
+ return true;
+ }
+ return false;
+ }
+
+ int keySize = 1;
+ KDColor lastColor = m_textColor;
+ switch (*(colorStart+1))
+ {
+ case 'r':
+ if (*(colorStart+2) == 'l') {
+ m_textColor = Palette::RedLight;
+ keySize = 2;
+ }
+ else {
+ m_textColor = Palette::Red;
+ }
+ break;
+ case 'm':
+ m_textColor = Palette::Magenta;
+ break;
+ case 't':
+ m_textColor = Palette::Turquoise;
+ break;
+ case 'p':
+ if (*(colorStart+2) == 'k') {
+ m_textColor = Palette::Pink;
+ keySize = 2;
+ }
+ else if (*(colorStart+2) == 'p') {
+ m_textColor = Palette::Purple;
+ keySize = 2;
+ }
+ break;
+ case 'b':
+ if (*(colorStart+2) == 'r') {
+ m_textColor = Palette::Brown;
+ keySize = 2;
+ }
+ else if (*(colorStart+2) == 'l') {
+ m_textColor = Palette::BlueLight;
+ keySize = 2;
+ }
+ else {
+ m_textColor = Palette::Blue;
+ }
+ break;
+ case 'o':
+ m_textColor = Palette::Orange;
+ break;
+ case 'g':
+ if (*(colorStart+2) == 'l') {
+ m_textColor = Palette::GreenLight;
+ keySize = 2;
+ }
+ else {
+ m_textColor = Palette::Green;
+ }
+ break;
+ case 'c':
+ m_textColor = Palette::Cyan;
+ break;
+
+ default:
+ return false;
+ }
+
+ if (*(colorStart + keySize + 1) != '%') {
+ m_textColor = lastColor;
+ return false;
+ }
+
+ return true;
+}
+
+}
diff --git a/apps/reader/word_wrap_view.h b/apps/reader/word_wrap_view.h
new file mode 100644
index 00000000000..c50dba12674
--- /dev/null
+++ b/apps/reader/word_wrap_view.h
@@ -0,0 +1,52 @@
+#ifndef _WORD_WRAP_VIEW_H_
+#define _WORD_WRAP_VIEW_H_
+
+#include
+#include
+
+namespace Reader
+{
+
+struct BookSave {
+ int offset;
+ KDColor color;
+};
+
+class ReadBookController;
+
+class WordWrapTextView : public PointerTextView {
+public:
+ WordWrapTextView(ReadBookController * readBookController);
+ void drawRect(KDContext * ctx, KDRect rect) const override;
+ void setText(const char*, int length, bool isRichTextFile);
+ void nextPage();
+ void previousPage();
+ BookSave getBookSave() const;
+ void setBookSave(BookSave save);
+private:
+ void richTextPreviousPage();
+ void plainTextPreviousPage();
+ void richTextDrawRect(KDContext * ctx, KDRect rect) const;
+ void plainTextDrawRect(KDContext * ctx, KDRect rect) const;
+ bool updateTextColorForward(const char * colorStart) const;
+ bool updateTextColorBackward(const char * colorStart) const;
+ static const int k_margin = 10;
+ static const int k_lastOffsetsBufferSize = 10;
+ int m_pageOffset;
+ mutable int m_nextPageOffset;
+ int m_length;
+ bool m_isRichTextFile;
+ mutable KDColor m_textColor;
+ /*
+ * Beacause the text that we draw can be of different sizes, we can't
+ * exactly know where the last page starts.
+ * So we store into a buffer (a cyclic stack) the offsets of the last pages.
+ */
+ int m_lastPagesOffsets[k_lastOffsetsBufferSize];
+ int m_lastPagesOffsetsIndex;
+ ReadBookController * m_readBookController;
+};
+
+}
+
+#endif
diff --git a/apps/regression/go_to_parameter_controller.cpp b/apps/regression/go_to_parameter_controller.cpp
index 461f98bfadb..984ebbfcd1e 100644
--- a/apps/regression/go_to_parameter_controller.cpp
+++ b/apps/regression/go_to_parameter_controller.cpp
@@ -67,7 +67,7 @@ bool GoToParameterController::confirmParameterAtIndex(int parameterIndex, double
} else {
double yFromX = m_store->modelForSeries(series)->evaluate(m_store->coefficientsForSeries(series, globContext), unknown);
/* We here compute y2 = a*((y1-b)/a)+b, which does not always give y1,
- * because of computation precision. y2 migth thus be invalid. */
+ * because of computation precision. y2 might thus be invalid. */
if (std::isnan(yFromX) || std::isinf(yFromX)) {
Container::activeApp()->displayWarning(I18n::Message::ForbiddenValue);
return false;
diff --git a/apps/regression/graph_options_controller.cpp b/apps/regression/graph_options_controller.cpp
index 83d80db4343..70770ae0511 100644
--- a/apps/regression/graph_options_controller.cpp
+++ b/apps/regression/graph_options_controller.cpp
@@ -118,7 +118,7 @@ void GraphOptionsController::willDisplayCellForIndex(HighlightCell * cell, int i
return;
}
assert(index >=0 && index < k_numberOfParameterCells);
- MessageTableCellWithChevron * myCell = (MessageTableCellWithChevron *)cell;
+ MessageTableCellWithChevron<> * myCell = (MessageTableCellWithChevron<> *)cell;
I18n::Message titles[k_numberOfParameterCells] = {I18n::Message::XPrediction, I18n::Message::YPrediction};
myCell->setMessage(titles[index]);
}
diff --git a/apps/regression/graph_options_controller.h b/apps/regression/graph_options_controller.h
index 69ec697bf63..202c4d2f806 100644
--- a/apps/regression/graph_options_controller.h
+++ b/apps/regression/graph_options_controller.h
@@ -32,7 +32,7 @@ class GraphOptionsController : public ViewController, public ListViewDataSource,
constexpr static int k_regressionCellType = 0;
constexpr static int k_parameterCelltype = 1;
constexpr static int k_numberOfParameterCells = 2;
- MessageTableCellWithChevron m_parameterCells[k_numberOfParameterCells];
+ MessageTableCellWithChevron<> m_parameterCells[k_numberOfParameterCells];
MessageTableCellWithChevronAndExpression m_changeRegressionCell;
SelectableTableView m_selectableTableView;
GoToParameterController m_goToParameterController;
diff --git a/apps/regression/model/model.h b/apps/regression/model/model.h
index 1b36fa6a8a0..149cad00b34 100644
--- a/apps/regression/model/model.h
+++ b/apps/regression/model/model.h
@@ -45,7 +45,7 @@ class Model {
Poincare::Layout m_layout;
private:
// Model attributes
- virtual Poincare::Expression expression(double * modelCoefficients) { return Poincare::Expression(); } // expression is overrided only by Models that do not override levelSet
+ virtual Poincare::Expression expression(double * modelCoefficients) { return Poincare::Expression(); } // expression is overridden only by Models that do not override levelSet
virtual double partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const = 0;
// Levenberg-Marquardt
diff --git a/apps/regression/test/model.cpp b/apps/regression/test/model.cpp
index eebec477603..4fcb7cdb1ae 100644
--- a/apps/regression/test/model.cpp
+++ b/apps/regression/test/model.cpp
@@ -190,7 +190,7 @@ QUIZ_CASE(power_regression) {
// assert_regression_is(x2, y2, 4, Model::Type::Power, coefficients2, r22);
}
-void assert_trigonomatric_regression_is(double * xi, double * yi, int numberOfPoints, double * trueCoefficients, double trueR2, Poincare::Preferences::AngleUnit trueCoeffcientsUnit) {
+void assert_trigonometric_regression_is(double * xi, double * yi, int numberOfPoints, double * trueCoefficients, double trueR2, Poincare::Preferences::AngleUnit trueCoeffcientsUnit) {
// Test the trigonometric regression at all angle units
const Preferences::AngleUnit previousAngleUnit = Preferences::sharedPreferences()->angleUnit();
const Poincare::Preferences::AngleUnit units[3] = {Poincare::Preferences::AngleUnit::Radian, Poincare::Preferences::AngleUnit::Degree, Poincare::Preferences::AngleUnit::Gradian};
@@ -214,7 +214,7 @@ QUIZ_CASE(trigonometric_regression1) {
int numberOfPoints = sizeof(x) / sizeof(double);
assert(sizeof(y) == sizeof(double) * numberOfPoints);
- assert_trigonomatric_regression_is(x, y, numberOfPoints, coefficients, r2, Poincare::Preferences::AngleUnit::Radian);
+ assert_trigonometric_regression_is(x, y, numberOfPoints, coefficients, r2, Poincare::Preferences::AngleUnit::Radian);
}
QUIZ_CASE(trigonometric_regression2) {
@@ -225,7 +225,7 @@ QUIZ_CASE(trigonometric_regression2) {
int numberOfPoints = sizeof(x) / sizeof(double);
assert(sizeof(y) == sizeof(double) * numberOfPoints);
- assert_trigonomatric_regression_is(x, y, numberOfPoints, coefficients, r2, Poincare::Preferences::AngleUnit::Radian);
+ assert_trigonometric_regression_is(x, y, numberOfPoints, coefficients, r2, Poincare::Preferences::AngleUnit::Radian);
}
diff --git a/apps/rpn b/apps/rpn
index 67d66295b0a..908ab20719d 160000
--- a/apps/rpn
+++ b/apps/rpn
@@ -1 +1 @@
-Subproject commit 67d66295b0a5a9bc5daf52412db9ae2ac87bbf57
+Subproject commit 908ab20719de2d8f30d9fc2da5220f502ef014fb
diff --git a/apps/sequence/base.de.i18n b/apps/sequence/base.de.i18n
index 88f518ca92b..21da2aeabd6 100644
--- a/apps/sequence/base.de.i18n
+++ b/apps/sequence/base.de.i18n
@@ -17,6 +17,5 @@ NEnd = "Endwert"
TermSum = "Summe der Terme"
SelectFirstTerm = "Erster Term "
SelectLastTerm = "Letzter Term "
-ValueNotReachedBySequence = "Wert wird von Folge nicht erreicht"
NColumn = "n-te Spalte"
FirstTermIndex = "Anfangsindex"
diff --git a/apps/sequence/base.en.i18n b/apps/sequence/base.en.i18n
index e9917698c8d..8776d4b7910 100644
--- a/apps/sequence/base.en.i18n
+++ b/apps/sequence/base.en.i18n
@@ -17,6 +17,5 @@ NEnd = "N end"
TermSum = "Sum of terms"
SelectFirstTerm = "Select First Term "
SelectLastTerm = "Select last term "
-ValueNotReachedBySequence = "Value not reached by sequence"
NColumn = "n column"
FirstTermIndex = "First term index"
diff --git a/apps/sequence/base.es.i18n b/apps/sequence/base.es.i18n
index 4bf2fe4929b..691b286b249 100644
--- a/apps/sequence/base.es.i18n
+++ b/apps/sequence/base.es.i18n
@@ -17,6 +17,5 @@ NEnd = "N fin"
TermSum = "Suma de términos"
SelectFirstTerm = "Seleccionar el primer término "
SelectLastTerm = "Seleccionar el último término "
-ValueNotReachedBySequence = "No se alcanza este valor"
NColumn = "Columna n"
FirstTermIndex = "Índice del primer término"
diff --git a/apps/sequence/base.fr.i18n b/apps/sequence/base.fr.i18n
index 3772efb4713..09d8bfa9da9 100644
--- a/apps/sequence/base.fr.i18n
+++ b/apps/sequence/base.fr.i18n
@@ -17,6 +17,5 @@ NEnd = "N fin"
TermSum = "Somme des termes"
SelectFirstTerm = "Sélectionner le premier terme "
SelectLastTerm = "Sélectionner le dernier terme "
-ValueNotReachedBySequence = "Valeur non atteinte par la suite"
NColumn = "Colonne n"
FirstTermIndex = "Indice premier terme"
diff --git a/apps/sequence/base.hu.i18n b/apps/sequence/base.hu.i18n
index f98ed2366d8..b52a13cfaf0 100644
--- a/apps/sequence/base.hu.i18n
+++ b/apps/sequence/base.hu.i18n
@@ -1,22 +1,21 @@
-SequenceApp = "Szekvenciák"
-SequenceAppCapital = "SZEKVENCIÁK"
-SequenceTab = "Szekvenciák"
-AddSequence = "Szekvencia hozzáadása"
-ChooseSequenceType = "Válassza ki a sorozat típusát"
-SequenceType = "Szekvencia típusa"
-Explicit = "Explicit kifejezés"
-SingleRecurrence = "Rekurzív elsö sorrend"
-DoubleRecurrence = "Rekurzív második sorrend"
-SequenceOptions = "Szekvencia opciók"
-SequenceColor = "Szekvencia színe"
-DeleteSequence = "Sorozat törlése"
-NoSequence = "Nincs sorrend"
-NoActivatedSequence = "Nincs szekvencia bekapcsolva"
-NStart = "N start"
-NEnd = "N vég"
-TermSum = "A kifejezés összege"
-SelectFirstTerm = "Elsö kifejezés kiválasztása "
-SelectLastTerm = "Utolsó kifejezés kiválasztása "
-ValueNotReachedBySequence = "Az értéket nem érte el a sorozat"
-NColumn = "n oszlop"
-FirstTermIndex = "Elsö kifejezés index"
+SequenceApp = "Szekvenciák"
+SequenceAppCapital = "SZEKVENCIÁK"
+SequenceTab = "Szekvenciák"
+AddSequence = "Szekvencia hozzáadása"
+ChooseSequenceType = "Válassza ki a sorozat típusát"
+SequenceType = "Szekvencia típusa"
+Explicit = "Explicit kifejezés"
+SingleRecurrence = "Rekurzív elsö sorrend"
+DoubleRecurrence = "Rekurzív második sorrend"
+SequenceOptions = "Szekvencia opciók"
+SequenceColor = "Szekvencia színe"
+DeleteSequence = "Sorozat törlése"
+NoSequence = "Nincs sorrend"
+NoActivatedSequence = "Nincs szekvencia bekapcsolva"
+NStart = "N start"
+NEnd = "N vég"
+TermSum = "A kifejezés összege"
+SelectFirstTerm = "Elsö kifejezés kiválasztása "
+SelectLastTerm = "Utolsó kifejezés kiválasztása "
+NColumn = "n oszlop"
+FirstTermIndex = "Elsö kifejezés index"
diff --git a/apps/sequence/base.it.i18n b/apps/sequence/base.it.i18n
index d9ddac4a1bf..3d714acfeac 100644
--- a/apps/sequence/base.it.i18n
+++ b/apps/sequence/base.it.i18n
@@ -17,6 +17,5 @@ NEnd = "N finale"
TermSum = "Somma dei termini"
SelectFirstTerm = "Selezionare il primo termine "
SelectLastTerm = "Selezionare l'ultimo termine "
-ValueNotReachedBySequence = "Valore non raggiunto dalla successione"
NColumn = "Colonna n"
FirstTermIndex = "Indice del primo termine"
diff --git a/apps/sequence/base.nl.i18n b/apps/sequence/base.nl.i18n
index 34a63d53d43..178761f1d40 100644
--- a/apps/sequence/base.nl.i18n
+++ b/apps/sequence/base.nl.i18n
@@ -17,6 +17,5 @@ NEnd = "N einde"
TermSum = "Som van termen"
SelectFirstTerm = "Selecteer eerste term "
SelectLastTerm = "Selecteer laatste term "
-ValueNotReachedBySequence = "Waarde niet bereikt door de rij"
NColumn = "n-kolom"
FirstTermIndex = "Eerste termindex"
diff --git a/apps/sequence/base.pt.i18n b/apps/sequence/base.pt.i18n
index 97f6580f8dd..3cfbb3338a7 100644
--- a/apps/sequence/base.pt.i18n
+++ b/apps/sequence/base.pt.i18n
@@ -17,6 +17,5 @@ NEnd = "N fim"
TermSum = "Soma dos termos"
SelectFirstTerm = "Selecionar primeiro termo "
SelectLastTerm = "Selecionar último termo "
-ValueNotReachedBySequence = "O valor não é alcançado pela sequência"
NColumn = "Coluna n"
FirstTermIndex = "Índice do primeiro termo"
diff --git a/apps/sequence/graph/curve_parameter_controller.h b/apps/sequence/graph/curve_parameter_controller.h
index 7d47f1f6d11..c47af5a3dad 100644
--- a/apps/sequence/graph/curve_parameter_controller.h
+++ b/apps/sequence/graph/curve_parameter_controller.h
@@ -20,7 +20,7 @@ class CurveParameterController : public Shared::FunctionCurveParameterController
constexpr static int k_totalNumberOfCells = 2;
GoToParameterController * goToParameterController() override;
GoToParameterController m_goToParameterController;
- MessageTableCell m_sumCell;
+ MessageTableCell<> m_sumCell;
GraphController * m_graphController;
};
diff --git a/apps/sequence/list/list_controller.h b/apps/sequence/list/list_controller.h
index d16af18d9cd..9aef7c4adf0 100644
--- a/apps/sequence/list/list_controller.h
+++ b/apps/sequence/list/list_controller.h
@@ -25,6 +25,8 @@ class ListController : public Shared::FunctionListController, public Shared::Inp
Toolbox * toolboxForInputEventHandler(InputEventHandler * handler) override;
void selectPreviousNewSequenceCell();
void editExpression(int sequenceDefinitionIndex, Ion::Events::Event event);
+protected:
+ virtual const char * recordExtension() const override { return Ion::Storage::seqExtension; }
private:
static constexpr KDCoordinate k_expressionCellVerticalMargin = 3;
bool editInitialConditionOfSelectedRecordWithText(const char * text, bool firstInitialCondition);
diff --git a/apps/sequence/list/list_parameter_controller.cpp b/apps/sequence/list/list_parameter_controller.cpp
index 9058083e3c9..2ac1397cd62 100644
--- a/apps/sequence/list/list_parameter_controller.cpp
+++ b/apps/sequence/list/list_parameter_controller.cpp
@@ -24,38 +24,18 @@ const char * ListParameterController::title() {
bool ListParameterController::handleEvent(Ion::Events::Event event) {
bool hasAdditionalRow = hasInitialRankRow();
-#if FUNCTION_COLOR_CHOICE
- if (event == Ion::Events::OK || event == Ion::Events::EXE || (event == Ion::Events::Right && selectedRow() == 1)) {
-#else
if (event == Ion::Events::OK || event == Ion::Events::EXE || (event == Ion::Events::Right && selectedRow() == 0)) {
-#endif
int selectedRowIndex = selectedRow();
-#if FUNCTION_COLOR_CHOICE
if (selectedRowIndex == 0) {
- return handleEnterOnRow(selectedRowIndex);
- }
- if (selectedRowIndex == 1) {
-#else
- if (selectedRowIndex == 0) {
-#endif
StackViewController * stack = (StackViewController *)(parentResponder());
m_typeParameterController.setRecord(m_record);
stack->push(&m_typeParameterController);
return true;
}
-#if FUNCTION_COLOR_CHOICE
- if (selectedRowIndex == 2+hasAdditionalRow) {
-
-#else
- if (selectedRowIndex == 1+hasAdditionalRow) {
-#endif
+ if (selectedRowIndex == 1+hasAdditionalRow || selectedRowIndex == 2+hasAdditionalRow) {
return handleEnterOnRow(selectedRowIndex-hasAdditionalRow-1);
}
-#if FUNCTION_COLOR_CHOICE
if (selectedRowIndex == 3+hasAdditionalRow) {
-#else
- if (selectedRowIndex == 2+hasAdditionalRow) {
-#endif
App::app()->localContext()->resetCache();
return handleEnterOnRow(selectedRowIndex-hasAdditionalRow-1);
}
diff --git a/apps/sequence/list/list_parameter_controller.h b/apps/sequence/list/list_parameter_controller.h
index 911630a0c8e..06166e8b0b7 100644
--- a/apps/sequence/list/list_parameter_controller.h
+++ b/apps/sequence/list/list_parameter_controller.h
@@ -25,11 +25,7 @@ class ListParameterController : public Shared::ListParameterController, public S
HighlightCell * reusableCell(int index, int type) override;
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
private:
-#if FUNCTION_COLOR_CHOICE
constexpr static int k_totalNumberOfCell = 5;
-#else
- constexpr static int k_totalNumberOfCell = 4;
-#endif
int totalNumberOfCells() const override;
Shared::Sequence * sequence() { return static_cast(function().pointer()); }
bool hasInitialRankRow() const;
diff --git a/apps/sequence/list/type_parameter_controller.cpp b/apps/sequence/list/type_parameter_controller.cpp
index e7ad0c56e9d..90cee0d7ccc 100644
--- a/apps/sequence/list/type_parameter_controller.cpp
+++ b/apps/sequence/list/type_parameter_controller.cpp
@@ -17,7 +17,7 @@ TypeParameterController::TypeParameterController(Responder * parentResponder, Li
ViewController(parentResponder),
m_explicitCell(&m_selectableTableView, I18n::Message::Explicit, cellLayout),
m_singleRecurrenceCell(&m_selectableTableView, I18n::Message::SingleRecurrence, cellLayout),
- m_doubleRecurenceCell(&m_selectableTableView, I18n::Message::DoubleRecurrence, cellLayout),
+ m_doubleRecurrenceCell(&m_selectableTableView, I18n::Message::DoubleRecurrence, cellLayout),
m_layouts{},
m_selectableTableView(this),
m_record(),
@@ -100,7 +100,7 @@ int TypeParameterController::numberOfRows() const {
HighlightCell * TypeParameterController::reusableCell(int index) {
assert(index >= 0);
assert(index < k_totalNumberOfCell);
- HighlightCell * cells[] = {&m_explicitCell, &m_singleRecurrenceCell, &m_doubleRecurenceCell};
+ HighlightCell * cells[] = {&m_explicitCell, &m_singleRecurrenceCell, &m_doubleRecurrenceCell};
return cells[index];
}
diff --git a/apps/sequence/list/type_parameter_controller.h b/apps/sequence/list/type_parameter_controller.h
index f6bf68862fc..f4d18d3ac26 100644
--- a/apps/sequence/list/type_parameter_controller.h
+++ b/apps/sequence/list/type_parameter_controller.h
@@ -36,7 +36,7 @@ class TypeParameterController : public ViewController, public SimpleListViewData
constexpr static int k_totalNumberOfCell = 3;
ExpressionTableCellWithPointer m_explicitCell;
ExpressionTableCellWithPointer m_singleRecurrenceCell;
- ExpressionTableCellWithPointer m_doubleRecurenceCell;
+ ExpressionTableCellWithPointer m_doubleRecurrenceCell;
Poincare::Layout m_layouts[k_totalNumberOfCell];
SelectableTableView m_selectableTableView;
Ion::Storage::Record m_record;
diff --git a/apps/sequence/test/sequence.cpp b/apps/sequence/test/sequence.cpp
index fb729ab14c1..3a390d6a651 100644
--- a/apps/sequence/test/sequence.cpp
+++ b/apps/sequence/test/sequence.cpp
@@ -47,7 +47,7 @@ void check_sequences_defined_by(double result[MaxNumberOfSequences][10], Sequenc
}
}
store->removeAll();
- /* The store is a global variable that has been contructed through
+ /* The store is a global variable that has been constructed through
* GlobalContext::sequenceStore singleton. It won't be destructed. However,
* we need to make sure that the pool is empty between quiz_cases. */
store->tidy();
diff --git a/apps/settings/Makefile b/apps/settings/Makefile
index 588b95c2f1c..5380cec810c 100644
--- a/apps/settings/Makefile
+++ b/apps/settings/Makefile
@@ -11,6 +11,7 @@ app_settings_src = $(addprefix apps/settings/,\
main_controller_prompt_update.cpp:+update \
sub_menu/about_controller.cpp \
sub_menu/accessibility_controller.cpp \
+ sub_menu/code_options_controller.cpp \
sub_menu/about_controller_official.cpp:+official \
sub_menu/about_controller_non_official.cpp:-official \
sub_menu/exam_mode_controller_official.cpp:+official \
@@ -24,6 +25,8 @@ app_settings_src = $(addprefix apps/settings/,\
sub_menu/contributors_controller.cpp \
sub_menu/math_options_controller.cpp \
sub_menu/selectable_view_with_messages.cpp \
+ sub_menu/external_controller.cpp \
+ sub_menu/brightness_controller.cpp\
)
SFLAGS += -DOMEGA_STATE="$(OMEGA_STATE)"
@@ -31,6 +34,6 @@ SFLAGS += -DOMEGA_STATE="$(OMEGA_STATE)"
app_settings_src += $(app_settings_test_src)
apps_src += $(app_settings_src)
-i18n_files += $(call i18n_without_universal_for,settings/base)
+i18n_files += $(call i18n_with_universal_for,settings/base)
$(eval $(call depends_on_image,apps/settings/app.cpp,apps/settings/settings_icon.png))
diff --git a/apps/settings/base.de.i18n b/apps/settings/base.de.i18n
index 5c00526fc3e..8f8cd5898b2 100644
--- a/apps/settings/base.de.i18n
+++ b/apps/settings/base.de.i18n
@@ -32,7 +32,9 @@ Real = "Reell "
Cartesian = "Kartesisch "
Polar = "Polar "
Brightness = "Helligkeit"
+BrightnessSettings = "Helligkeitseinstellungen"
SoftwareVersion = "Epsilon version"
+UpsilonVersion = "Upsilon version"
OmegaVersion = "Omega version"
Username = "Name"
MicroPythonVersion = "µPythonversion"
@@ -43,6 +45,7 @@ SerialNumber = "Seriennummer"
UpdatePopUp = "Erinnerung: Aktualisierung"
BetaPopUp = "Erinnerung: Vorabversion"
Contributors = "Mitwirkende"
+Battery = "Batteriestatus"
Accessibility = "Barrierefreiheit"
AccessibilityInvertColors = "Farbumkehrung"
AccessibilityMagnify = "Lupe"
@@ -60,11 +63,21 @@ SymbolFunction = "Ausdrucksformat "
SymbolDefaultFunction = "Standardl "
SymbolArgFunction = "Leer "
SymbolArgDefaultFunction = "Argument "
-PythonFont = "Python Schriftart"
MemUse = "Speicher"
DateTime = "Datum/Uhrzeit"
+ExternalApps = "Externe Apps"
ActivateClock = "Uhr aktivieren"
Date = "Datum"
Time = "Uhrzeit"
RTCWarning1 = "Das Aktivieren der Uhr verkürzt die"
RTCWarning2 = "Akkulaufzeit im Bereitschaftsmodus."
+SyntaxHighlighting = "Syntaxhervorhebung"
+Normal = "Normal"
+IdleTimeBeforeDimming = "Abdunkeln nach (s)"
+IdleTimeBeforeSuspend = "Anhalten nach (s)"
+BrightnessShortcut = "Tastenkombinationsschritte"
+ExtAppWrite = "Schreiben aktiviert"
+ExtAppWriteExplanation1 = "Standardmäßig externe Anwendungen"
+ExtAppWriteExplanation2 = "kann nicht in den Speicher schreiben"
+ExtAppWriteExplanation3 = "Flash (dauerhaft) Ihres Rechners."
+ExtAppEnabled = "Aufstecken"
diff --git a/apps/settings/base.en.i18n b/apps/settings/base.en.i18n
index b5d07690485..56f15205480 100644
--- a/apps/settings/base.en.i18n
+++ b/apps/settings/base.en.i18n
@@ -32,7 +32,9 @@ Real = "Real "
Cartesian = "Cartesian "
Polar = "Polar "
Brightness = "Brightness"
+BrightnessSettings = "Brightness settings"
SoftwareVersion = "Epsilon version"
+UpsilonVersion = "Upsilon version"
OmegaVersion = "Omega version"
Username = "Name"
MicroPythonVersion = "µPython version"
@@ -42,6 +44,7 @@ SmallFont = "Small "
SerialNumber = "Serial number"
UpdatePopUp = "Update pop-up"
BetaPopUp = "Beta pop-up"
+Battery = "Battery"
Contributors = "Contributors"
Accessibility = "Accessibility"
AccessibilityInvertColors = "Invert colors"
@@ -60,11 +63,21 @@ SymbolFunction = "Expression format "
SymbolDefaultFunction = "Default "
SymbolArgFunction = "Empty "
SymbolArgDefaultFunction = "Argument "
-PythonFont = "Python Font"
MemUse = "Memory"
DateTime = "Date/time"
+ExternalApps = "External Apps"
ActivateClock = "Activate clock"
Date = "Date"
Time = "Time"
RTCWarning1 = "Enabling the clock drains the battery faster"
RTCWarning2 = "when the calculator is powered off."
+SyntaxHighlighting = "Syntax Highlighting"
+Normal = "Normal"
+IdleTimeBeforeDimming = "Dim after (s)"
+IdleTimeBeforeSuspend = "Suspend after (s)"
+BrightnessShortcut = "Shortcut steps"
+ExtAppWrite = "Write allowed"
+ExtAppWriteExplanation1 = "By default, external applications"
+ExtAppWriteExplanation2 = "cannot write to memory"
+ExtAppWriteExplanation3 = "flash (persistent) of your calculator."
+ExtAppEnabled = "Pin up"
diff --git a/apps/settings/base.es.i18n b/apps/settings/base.es.i18n
index 944709570f0..42ce777f24e 100644
--- a/apps/settings/base.es.i18n
+++ b/apps/settings/base.es.i18n
@@ -32,7 +32,9 @@ Real = "Real "
Cartesian = "Binómica "
Polar = "Polar "
Brightness = "Brillo"
+BrightnessSettings = "Configuración de brillo"
SoftwareVersion = "Versión de Epsilon"
+UpsilonVersion = "Versión de Upsilon"
OmegaVersion = "Versión de Omega"
Username = "Apellido"
MicroPythonVersion = "Version de µPython"
@@ -43,6 +45,7 @@ SerialNumber = "Número serie"
UpdatePopUp = "Pop-up de actualización"
BetaPopUp = "Beta pop-up"
Contributors = "Contribuyentes"
+Battery = "Batería"
Accessibility = "Accesibilidad"
AccessibilityInvertColors = "Colores invertidos"
AccessibilityMagnify = "Lupa"
@@ -60,11 +63,21 @@ SymbolFunction = "Formato expresión "
SymbolDefaultFunction = "Defecto "
SymbolArgFunction = "Vacío "
SymbolArgDefaultFunction = "Argumento "
-PythonFont = "Fuente Python"
MemUse = "Memoria"
DateTime = "Fecha/Hora"
+ExternalApps = "Aplicaciones externas"
ActivateClock = "Activar el reloj"
Date = "Fecha"
Time = "Hora"
RTCWarning1 = "Activar el reloj gasta la batería más rápido"
RTCWarning2 = "cuando la calculadora está apagada."
+SyntaxHighlighting = "Resaltado de sintaxis"
+Normal = "Normal"
+IdleTimeBeforeDimming = "Oscurecer después de (s)"
+IdleTimeBeforeSuspend = "Suspender después de (s)"
+BrightnessShortcut = "Pasos de acceso directo"
+ExtAppWrite = "Escritura habilitada"
+ExtAppWriteExplanation1 = "Por defecto, las aplicaciones externas"
+ExtAppWriteExplanation2 = "no se puede escribir en la memoria"
+ExtAppWriteExplanation3 = "flash (persistente) de su calculadora."
+ExtAppEnabled = "Fijar"
diff --git a/apps/settings/base.fr.i18n b/apps/settings/base.fr.i18n
index ac76c7dca0d..676e64687ca 100644
--- a/apps/settings/base.fr.i18n
+++ b/apps/settings/base.fr.i18n
@@ -32,7 +32,9 @@ Real = "Réel "
Cartesian = "Algébrique "
Polar = "Exponentielle "
Brightness = "Luminosité"
+BrightnessSettings = "Paramètres de luminosité"
SoftwareVersion = "Version d'Epsilon"
+UpsilonVersion = "Version d'Upsilon"
OmegaVersion = "Version d'Omega"
Username = "Nom"
MicroPythonVersion = "Version de µPython"
@@ -43,6 +45,7 @@ SerialNumber = "Numéro de série"
UpdatePopUp = "Rappel de mise à jour"
BetaPopUp = "Rappel de version bêta"
Contributors = "Contributeurs"
+Battery = "Batterie"
Accessibility = "Accessibilité"
AccessibilityInvertColors = "Inverser couleurs"
AccessibilityMagnify = "Loupe"
@@ -60,11 +63,21 @@ SymbolFunction = "Format expression "
SymbolDefaultFunction = "Défaut "
SymbolArgFunction = "Vide "
SymbolArgDefaultFunction = "Arguments "
-PythonFont = "Police Python"
MemUse = "Mémoire"
DateTime = "Date/heure"
+ExternalApps = "Applications externes"
ActivateClock = "Activer horloge"
Date = "Date"
Time = "Heure"
RTCWarning1 = "Activer l'horloge décharge la batterie plus"
RTCWarning2 = "vite quand la calculatrice est éteinte."
+SyntaxHighlighting = "Coloration syntaxique"
+Normal = "Normale"
+IdleTimeBeforeDimming = "Assombrir après (s)"
+IdleTimeBeforeSuspend = "Éteindre après (s)"
+BrightnessShortcut = "Étapes du raccourci"
+ExtAppWrite = "Écriture autorisée"
+ExtAppWriteExplanation1 = "Par défaut, les applications externes"
+ExtAppWriteExplanation2 = "ne peuvent écrire dans la mémoire"
+ExtAppWriteExplanation3 = "flash (persistante) de votre calculatrice."
+ExtAppEnabled = "Afficher"
diff --git a/apps/settings/base.hu.i18n b/apps/settings/base.hu.i18n
index 19ed3a67f63..a46e8cddaa0 100644
--- a/apps/settings/base.hu.i18n
+++ b/apps/settings/base.hu.i18n
@@ -1,70 +1,83 @@
-SettingsApp = "Beállítások"
-SettingsAppCapital = "BEÁLLÍTÁSOK"
-AngleUnit = "Szögmérö"
-DisplayMode = "Eredmény formátuma"
-EditionMode = "Írás formátuma"
-EditionLinear = "Lineáris"
-Edition2D = "Természetes"
-ComplexFormat = "Komplex formátum"
-ExamMode = "Vizsga mód"
-ExamModeActive = "A vizsgamód újraaktiválása"
-ToDeactivateExamMode1 = "a vizsga mód kikapcsoláshoz"
-ToDeactivateExamMode2 = "csatlakoztassa a számológépet a számítógéphez"
-ToDeactivateExamMode3 = "vagy egy konnektorhoz."
-# --------------------- Please do not edit these messages ---------------------
-ExamModeWarning1 = "Vigyázat: a használt szoftver nem"
-ExamModeWarning2 = "hivatalos, Numworks nem garantálja"
-ExamModeWarning3 = "a vizsgálati mód megfelelőségét."
-AboutWarning1 = "Vigyázat: a használt szoftver"
-AboutWarning2 = "nem hivatalos. A NumWorks nem"
-AboutWarning3 = "vállal felelösséget az"
-AboutWarning4 = "esetleges károkért."
-# -----------------------------------------------------------------------------
-About = "Apropó"
-Degrees = "Fokok "
-Gradians = "Gradiens "
-Radian = "Radián "
-Decimal = "Tizedes "
-Scientific = "Tudományos "
-Engineering = "Mérnökség "
-SignificantFigures = "Tizedes számok "
-Real = "Valódi "
-Cartesian = "Kartéziánus "
-Polar = "Poláris "
-Brightness = "Fényerö"
-SoftwareVersion = "Epsilon verzió"
-OmegaVersion = "Omega verzió"
-Username = "Felhasználónév"
-MicroPythonVersion = "µPython verzió"
-FontSizes = "Python betü méret"
-LargeFont = "Nagy "
-SmallFont = "Kicsi "
-SerialNumber = "Sorozatszám"
-UpdatePopUp = "Frissítés figyelmeztetés"
-BetaPopUp = "Béta figyelmeztetés"
-Contributors = "Közremüködök"
-Accessibility = "Több vizuális beállitások"
-AccessibilityInvertColors = "Invertált színek"
-AccessibilityMagnify = "Nagyító"
-AccessibilityGamma = "Gamma korrekció"
-AccessibilityGammaRed = "Piros gamma"
-AccessibilityGammaGreen = "Zöld gamma"
-AccessibilityGammaBlue = "Kék gamma"
-MathOptions = "Matematikai beállítások"
-SymbolMultiplication = "Szorzás"
-SymbolMultiplicationCross = "Kereszt "
-SymbolMultiplicationMiddleDot = "Pont "
-SymbolMultiplicationStar = "Csillag "
-SymbolMultiplicationAutoSymbol = "Automatitus "
-SymbolFunction = "Kifejezés "
-SymbolDefaultFunction = "Alap "
-SymbolArgFunction = "Üres "
-SymbolArgDefaultFunction = "Argumentummal "
-PythonFont = "Python Betütipus"
-MemUse = "Memória"
-DateTime = "Dátum/óra"
-ActivateClock = "Óra bekapcsolása"
-Date = "Datum"
-Time = "Óra"
-RTCWarning1 = "Amikor a számológép alvómódban van, az óra"
-RTCWarning2 = "használása az elemet gyorsabban meríti ki."
+SettingsApp = "Beállítások"
+SettingsAppCapital = "BEÁLLÍTÁSOK"
+AngleUnit = "Szögmérö"
+DisplayMode = "Eredmény formátuma"
+EditionMode = "Írás formátuma"
+EditionLinear = "Lineáris"
+Edition2D = "Természetes"
+ComplexFormat = "Komplex formátum"
+ExamMode = "Vizsga mód"
+ExamModeActive = "A vizsgamód újraaktiválása"
+ToDeactivateExamMode1 = "a vizsga mód kikapcsoláshoz"
+ToDeactivateExamMode2 = "csatlakoztassa a számológépet a számítógéphez"
+ToDeactivateExamMode3 = "vagy egy konnektorhoz."
+# --------------------- Please do not edit these messages ---------------------
+ExamModeWarning1 = "Vigyázat: a használt szoftver nem"
+ExamModeWarning2 = "hivatalos, Numworks nem garantálja"
+ExamModeWarning3 = "a vizsgálati mód megfelelőségét."
+AboutWarning1 = "Vigyázat: a használt szoftver"
+AboutWarning2 = "nem hivatalos. A NumWorks nem"
+AboutWarning3 = "vállal felelösséget az"
+AboutWarning4 = "esetleges károkért."
+# -----------------------------------------------------------------------------
+About = "Apropó"
+Degrees = "Fokok "
+Gradians = "Gradiens "
+Radian = "Radián "
+Decimal = "Tizedes "
+Scientific = "Tudományos "
+Engineering = "Mérnökség "
+SignificantFigures = "Tizedes számok "
+Real = "Valódi "
+Cartesian = "Kartéziánus "
+Polar = "Poláris "
+Brightness = "Fényerö"
+BrightnessSettings = "Fényerő beállításai"
+SoftwareVersion = "Epsilon verzió"
+UpsilonVersion = "Upsilon verzió"
+OmegaVersion = "Omega verzió"
+Username = "Felhasználónév"
+MicroPythonVersion = "µPython verzió"
+FontSizes = "Python betü méret"
+LargeFont = "Nagy "
+SmallFont = "Kicsi "
+SerialNumber = "Sorozatszám"
+UpdatePopUp = "Frissítés figyelmeztetés"
+BetaPopUp = "Béta figyelmeztetés"
+Contributors = "Közremüködök"
+Battery = "Akkumulátor"
+Accessibility = "Több vizuális beállitások"
+AccessibilityInvertColors = "Invertált színek"
+AccessibilityMagnify = "Nagyító"
+AccessibilityGamma = "Gamma korrekció"
+AccessibilityGammaRed = "Piros gamma"
+AccessibilityGammaGreen = "Zöld gamma"
+AccessibilityGammaBlue = "Kék gamma"
+MathOptions = "Matematikai beállítások"
+SymbolMultiplication = "Szorzás"
+SymbolMultiplicationCross = "Kereszt "
+SymbolMultiplicationMiddleDot = "Pont "
+SymbolMultiplicationStar = "Csillag "
+SymbolMultiplicationAutoSymbol = "Automatitus "
+SymbolFunction = "Kifejezés "
+SymbolDefaultFunction = "Alap "
+SymbolArgFunction = "Üres "
+SymbolArgDefaultFunction = "Argumentummal "
+MemUse = "Memória"
+DateTime = "Dátum/óra"
+ExternalApps = "Külső alkalmazások"
+ActivateClock = "Óra bekapcsolása"
+Date = "Datum"
+Time = "Óra"
+RTCWarning1 = "Amikor a számológép alvómódban van, az óra"
+RTCWarning2 = "használása az elemet gyorsabban meríti ki."
+SyntaxHighlighting = "Szintaxis kiemelés"
+Normal = "Normale"
+IdleTimeBeforeDimming = "Assombrir après (s)"
+IdleTimeBeforeSuspend = "Éteindre après (s)"
+BrightnessShortcut = "Parancsikon lépések"
+ExtAppWrite = "Írás engedélyezve"
+ExtAppWriteExplanation1 = "Alapértelmezés szerint külső alkalmazások"
+ExtAppWriteExplanation2 = "nem tud a memóriába írni"
+ExtAppWriteExplanation3 = "villog (tartósan) a számológép."
+ExtAppEnabled = "Feltűz"
diff --git a/apps/settings/base.it.i18n b/apps/settings/base.it.i18n
index 5c4dcc0a47c..76b7090850f 100644
--- a/apps/settings/base.it.i18n
+++ b/apps/settings/base.it.i18n
@@ -32,39 +32,52 @@ Real = "Reale "
Cartesian = "Algebrico "
Polar = "Esponenziale "
Brightness = "Luminosità"
-SoftwareVersion = "Epsilon version"
-OmegaVersion = "Omega version"
-Username = "Name"
-MicroPythonVersion = "µPython version"
+BrightnessSettings = "Impostazioni luminosità"
+SoftwareVersion = "Versione di Epsilon"
+UpsilonVersion = "Versione di Upsilon"
+OmegaVersion = "Versione di Omega"
+Username = "Nome"
+MicroPythonVersion = "Versione µPython"
FontSizes = "Carattere Python"
LargeFont = "Grande "
SmallFont = "Piccolo "
SerialNumber = "Numero di serie"
UpdatePopUp = "Promemoria aggiornamento"
BetaPopUp = "Promemoria beta"
-Contributors = "Contributors"
-Accessibility = "Accessibility"
-AccessibilityInvertColors = "Invert colors"
-AccessibilityMagnify = "Magnify"
-AccessibilityGamma = "Gamma correction"
-AccessibilityGammaRed = "Red gamma"
-AccessibilityGammaGreen = "Green gamma"
-AccessibilityGammaBlue = "Blue gamma"
-MathOptions = "Math options"
-SymbolMultiplication = "Multiply"
-SymbolMultiplicationCross = "Cross "
-SymbolMultiplicationMiddleDot = "Dot "
-SymbolMultiplicationStar = "Star "
-SymbolMultiplicationAutoSymbol = "Auto "
-SymbolFunction = "Expression format "
-SymbolDefaultFunction = "Default "
-SymbolArgFunction = "Empty "
-SymbolArgDefaultFunction = "Argument "
-PythonFont = "Python Font"
-MemUse = "Memory"
-DateTime = "Date/time"
-ActivateClock = "Activate clock"
-Date = "Date"
-Time = "Time"
-RTCWarning1 = "Enabling the clock drains the battery faster"
-RTCWarning2 = "when the calculator is powered off."
+Contributors = "Contributori"
+Battery = "Batteria"
+Accessibility = "Accessibilità"
+AccessibilityInvertColors = "Inversione colori"
+AccessibilityMagnify = "Ingrandimento"
+AccessibilityGamma = "Correzione gamma"
+AccessibilityGammaRed = "Gamma del rosso"
+AccessibilityGammaGreen = "Gamma del verde"
+AccessibilityGammaBlue = "Gamma del blu"
+MathOptions = "Opzioni matematica"
+SymbolMultiplication = "Simbolo moltiplicaz."
+SymbolMultiplicationCross = "Croce "
+SymbolMultiplicationMiddleDot = "Punto "
+SymbolMultiplicationStar = "Stella "
+SymbolMultiplicationAutoSymbol = "Automatico "
+SymbolFunction = "Formato espressioni "
+SymbolDefaultFunction = "Predefinito "
+SymbolArgFunction = "Vuoto "
+SymbolArgDefaultFunction = "Argomento "
+MemUse = "Memoria"
+DateTime = "Data/ora"
+ExternalApps = "App esterne"
+ActivateClock = "Attiva orologio"
+Date = "Data"
+Time = "Ora"
+RTCWarning1 = "Attivare l'orologio drena la batteria più"
+RTCWarning2 = "velocemente quando la calcolatrice è spenta."
+SyntaxHighlighting = "Evidenz. sintassi"
+Normal = "Normale"
+IdleTimeBeforeDimming = "Scurisci dopo (s)"
+IdleTimeBeforeSuspend = "Sospendi dopo (s)"
+BrightnessShortcut = "Livelli scelta rapida"
+ExtAppWrite = "Scrittura abilitata"
+ExtAppWriteExplanation1 = "Per impostazione predefinita, le app esterne"
+ExtAppWriteExplanation2 = "non possono scrivere in memoria flash"
+ExtAppWriteExplanation3 = "(persistente) della calcolatrice."
+ExtAppEnabled = "Affiggere"
diff --git a/apps/settings/base.nl.i18n b/apps/settings/base.nl.i18n
index 75939d6a877..f26e546c402 100644
--- a/apps/settings/base.nl.i18n
+++ b/apps/settings/base.nl.i18n
@@ -32,7 +32,9 @@ Real = "Reëel "
Cartesian = "Cartesisch "
Polar = "Polair "
Brightness = "Helderheid"
+BrightnessSettings = "Helderheidsinstellingen"
SoftwareVersion = "Epsilon version"
+UpsilonVersion = "Upsilon version"
OmegaVersion = "Omega version"
Username = "Name"
MicroPythonVersion = "µPython version"
@@ -43,6 +45,7 @@ SerialNumber = "Serienummer"
UpdatePopUp = "Update pop-up"
BetaPopUp = "Bèta pop-up"
Contributors = "Contributors"
+Battery = "Batterij"
Accessibility = "Accessibility"
AccessibilityInvertColors = "Invert colors"
AccessibilityMagnify = "Magnify"
@@ -60,11 +63,21 @@ SymbolFunction = "Expression format "
SymbolDefaultFunction = "Default "
SymbolArgFunction = "Empty "
SymbolArgDefaultFunction = "Argument "
-PythonFont = "Python Font"
MemUse = "Memory"
DateTime = "Date/time"
+ExternalApps = "Externe apps"
ActivateClock = "Activate clock"
Date = "Date"
Time = "Time"
RTCWarning1 = "Enabling the clock drains the battery faster"
RTCWarning2 = "when the calculator is powered off."
+SyntaxHighlighting = "Syntax Highlighting"
+Normal = "Normaal"
+IdleTimeBeforeDimming = "Donkerder maken na (s)"
+IdleTimeBeforeSuspend = "Suspend after (s)"
+BrightnessShortcut = "Snelkoppelingsstappen"
+ExtAppWrite = "Schrijven ingeschakeld"
+ExtAppWriteExplanation1 = "Standaard zijn externe toepassingen"
+ExtAppWriteExplanation2 = "kan niet naar het geheugen schrijven"
+ExtAppWriteExplanation3 = "flash (aanhoudend) van uw rekenmachine."
+ExtAppEnabled = "Vastpinnen"
diff --git a/apps/settings/base.pt.i18n b/apps/settings/base.pt.i18n
index f33006f4ad6..950bc992718 100644
--- a/apps/settings/base.pt.i18n
+++ b/apps/settings/base.pt.i18n
@@ -32,7 +32,9 @@ Real = "Real "
Cartesian = "Cartesiana "
Polar = "Polar "
Brightness = "Brilho"
+BrightnessSettings = "Configurações de brilho"
SoftwareVersion = "Versão do Epsilon"
+UpsilonVersion = "Versão do Upsilon"
OmegaVersion = "Versão do Omega"
Username = "Nome"
MicroPythonVersion = "Versao do µPython"
@@ -43,6 +45,7 @@ SerialNumber = "Número serie"
UpdatePopUp = "Alertas de atualização"
BetaPopUp = "Beta pop-up"
Contributors = "Contribuidores"
+Battery = "Bateria"
Accessibility = "Acessibilidade"
AccessibilityInvertColors = "Cores invertidas"
AccessibilityMagnify = "Lupa"
@@ -60,11 +63,21 @@ SymbolFunction = "Formato expressão "
SymbolDefaultFunction = "Padrão "
SymbolArgFunction = "Vazio "
SymbolArgDefaultFunction = "Argumento "
-PythonFont = "Fonte Python"
MemUse = "Memória"
DateTime = "Date/time"
+ExternalApps = "Aplicativos externos"
ActivateClock = "Activate clock"
Date = "Date"
Time = "Time"
RTCWarning1 = "Enabling the clock drains the battery faster"
RTCWarning2 = "when the calculator is powered off."
+SyntaxHighlighting = "Destaque da sintaxe"
+Normal = "Normal"
+IdleTimeBeforeDimming = "Diminuir depois (s)"
+IdleTimeBeforeSuspend = "Suspender depois (s)"
+BrightnessShortcut = "Passos de atalho"
+ExtAppWrite = "Gravação ativada"
+ExtAppWriteExplanation1 = "Por padrão, aplicativos externos"
+ExtAppWriteExplanation2 = "não pode gravar na memória"
+ExtAppWriteExplanation3 = "flash (persistente) de sua calculadora."
+ExtAppEnabled = "Pôster"
diff --git a/apps/settings/base.universal.i18n b/apps/settings/base.universal.i18n
new file mode 100644
index 00000000000..210e673fbaf
--- /dev/null
+++ b/apps/settings/base.universal.i18n
@@ -0,0 +1 @@
+UsbSetting = "USB"
diff --git a/apps/settings/main_controller.cpp b/apps/settings/main_controller.cpp
index 6b65f15d3ea..7e71771f93a 100644
--- a/apps/settings/main_controller.cpp
+++ b/apps/settings/main_controller.cpp
@@ -15,25 +15,35 @@ constexpr SettingsMessageTree s_modelFloatDisplayModeChildren[4] = {SettingsMess
constexpr SettingsMessageTree s_modelComplexFormatChildren[3] = {SettingsMessageTree(I18n::Message::Real), SettingsMessageTree(I18n::Message::Cartesian), SettingsMessageTree(I18n::Message::Polar)};
constexpr SettingsMessageTree s_modelDateTimeChildren[3] = {SettingsMessageTree(I18n::Message::ActivateClock), SettingsMessageTree(I18n::Message::Date), SettingsMessageTree(I18n::Message::Time)};
constexpr SettingsMessageTree s_symbolChildren[4] = {SettingsMessageTree(I18n::Message::SymbolMultiplicationCross),SettingsMessageTree(I18n::Message::SymbolMultiplicationMiddleDot),SettingsMessageTree(I18n::Message::SymbolMultiplicationStar),SettingsMessageTree(I18n::Message::SymbolMultiplicationAutoSymbol)};
+constexpr SettingsMessageTree s_externalChildren[2] = {SettingsMessageTree(I18n::Message::ExtAppWrite), SettingsMessageTree(I18n::Message::ExtAppEnabled)};
constexpr SettingsMessageTree s_symbolFunctionChildren[3] = {SettingsMessageTree(I18n::Message::SymbolDefaultFunction), SettingsMessageTree(I18n::Message::SymbolArgDefaultFunction), SettingsMessageTree(I18n::Message::SymbolArgFunction)};
constexpr SettingsMessageTree s_modelMathOptionsChildren[6] = {SettingsMessageTree(I18n::Message::AngleUnit, s_modelAngleChildren), SettingsMessageTree(I18n::Message::DisplayMode, s_modelFloatDisplayModeChildren), SettingsMessageTree(I18n::Message::EditionMode, s_modelEditionModeChildren), SettingsMessageTree(I18n::Message::SymbolFunction, s_symbolFunctionChildren), SettingsMessageTree(I18n::Message::ComplexFormat, s_modelComplexFormatChildren), SettingsMessageTree(I18n::Message::SymbolMultiplication, s_symbolChildren)};
-constexpr SettingsMessageTree s_modelFontChildren[2] = {SettingsMessageTree(I18n::Message::LargeFont), SettingsMessageTree(I18n::Message::SmallFont)};
+constexpr SettingsMessageTree s_brightnessChildren[4] = {SettingsMessageTree(I18n::Message::Brightness), SettingsMessageTree(I18n::Message::IdleTimeBeforeDimming), SettingsMessageTree(I18n::Message::IdleTimeBeforeSuspend), SettingsMessageTree(I18n::Message::BrightnessShortcut)};
constexpr SettingsMessageTree s_accessibilityChildren[6] = {SettingsMessageTree(I18n::Message::AccessibilityInvertColors), SettingsMessageTree(I18n::Message::AccessibilityMagnify),SettingsMessageTree(I18n::Message::AccessibilityGamma),SettingsMessageTree(I18n::Message::AccessibilityGammaRed),SettingsMessageTree(I18n::Message::AccessibilityGammaGreen),SettingsMessageTree(I18n::Message::AccessibilityGammaBlue)};
-constexpr SettingsMessageTree s_contributorsChildren[23] = {SettingsMessageTree(I18n::Message::Developers), SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::MaximeFriess), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::SandraSimmons), SettingsMessageTree(I18n::Message::David), SettingsMessageTree(I18n::Message::DamienNicolet), SettingsMessageTree(I18n::Message::EvannDreumont), SettingsMessageTree(I18n::Message::SzaboLevente), SettingsMessageTree(I18n::Message::VenceslasDuet), SettingsMessageTree(I18n::Message::CharlotteThomas), SettingsMessageTree(I18n::Message::AntoninLoubiere), SettingsMessageTree(I18n::Message::CyprienMejat), SettingsMessageTree(I18n::Message::BetaTesters), SettingsMessageTree(I18n::Message::TimeoArnouts), SettingsMessageTree(I18n::Message::JulieC), SettingsMessageTree(I18n::Message::LelahelHideux), SettingsMessageTree(I18n::Message::Madil), SettingsMessageTree(I18n::Message::HilaireLeRoux), SettingsMessageTree(I18n::Message::HectorNussbaumer), SettingsMessageTree(I18n::Message::RaphaelDyda), SettingsMessageTree(I18n::Message::ThibautC)};
-constexpr SettingsMessageTree s_modelAboutChildren[8] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::OmegaVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::MemUse), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren)};
+constexpr SettingsMessageTree s_contributorsChildren[18] = {SettingsMessageTree(I18n::Message::LaurianFournier), SettingsMessageTree(I18n::Message::YannCouturier), SettingsMessageTree(I18n::Message::DavidLuca), SettingsMessageTree(I18n::Message::LoicE), SettingsMessageTree(I18n::Message::VictorKretz), SettingsMessageTree(I18n::Message::QuentinGuidee), SettingsMessageTree(I18n::Message::JoachimLeFournis), SettingsMessageTree(I18n::Message::MaximeFriess), SettingsMessageTree(I18n::Message::JeanBaptisteBoric), SettingsMessageTree(I18n::Message::SandraSimmons), SettingsMessageTree(I18n::Message::David), SettingsMessageTree(I18n::Message::DamienNicolet), SettingsMessageTree(I18n::Message::EvannDreumont), SettingsMessageTree(I18n::Message::SzaboLevente), SettingsMessageTree(I18n::Message::VenceslasDuet), SettingsMessageTree(I18n::Message::CharlotteThomas), SettingsMessageTree(I18n::Message::AntoninLoubiere), SettingsMessageTree(I18n::Message::CyprienMejat)};
+
+// Code Settings
+#ifdef HAS_CODE
+constexpr SettingsMessageTree s_codeChildren[3] = {SettingsMessageTree(I18n::Message::FontSizes, s_modelFontChildren), SettingsMessageTree(I18n::Message::Autocomplete), SettingsMessageTree(I18n::Message::SyntaxHighlighting)};
+#endif
+constexpr SettingsMessageTree s_modelFontChildren[2] = {SettingsMessageTree(I18n::Message::LargeFont), SettingsMessageTree(I18n::Message::SmallFont)};
+
+constexpr SettingsMessageTree s_modelAboutChildren[10] = {SettingsMessageTree(I18n::Message::Username), SettingsMessageTree(I18n::Message::UpsilonVersion), SettingsMessageTree(I18n::Message::OmegaVersion), SettingsMessageTree(I18n::Message::SoftwareVersion), SettingsMessageTree(I18n::Message::MicroPythonVersion), SettingsMessageTree(I18n::Message::Battery), SettingsMessageTree(I18n::Message::MemUse), SettingsMessageTree(I18n::Message::SerialNumber), SettingsMessageTree(I18n::Message::FccId), SettingsMessageTree(I18n::Message::Contributors, s_contributorsChildren)};
MainController::MainController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate) :
ViewController(parentResponder),
- m_brightnessCell(I18n::Message::Default, KDFont::LargeFont),
m_popUpCell(I18n::Message::Default, KDFont::LargeFont),
m_selectableTableView(this),
m_mathOptionsController(this, inputEventHandlerDelegate),
+ m_brightnessController(this, inputEventHandlerDelegate),
m_localizationController(this, Metric::CommonTopMargin, LocalizationController::Mode::Language),
m_accessibilityController(this),
m_dateTimeController(this),
+ m_codeOptionsController(this),
m_examModeController(this),
m_aboutController(this),
- m_preferencesController(this)
+ m_preferencesController(this),
+ m_externalController(this)
{
for (int i = 0; i < k_numberOfSimpleChevronCells; i++) {
m_cells[i].setMessageFont(KDFont::LargeFont);
@@ -53,32 +63,15 @@ void MainController::didBecomeFirstResponder() {
bool MainController::handleEvent(Ion::Events::Event event) {
GlobalPreferences * globalPreferences = GlobalPreferences::sharedGlobalPreferences();
- if (event == Ion::Events::BrightnessPlus || event == Ion::Events::BrightnessMinus){
- int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates;
- int direction = (event == Ion::Events::BrightnessPlus) ? Ion::Backlight::NumberOfStepsPerShortcut*delta : -delta*Ion::Backlight::NumberOfStepsPerShortcut;
- GlobalPreferences::sharedGlobalPreferences()->setBrightnessLevel(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()+direction);
- m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), 1);
- return true;
- }
if (model()->childAtIndex(selectedRow())->numberOfChildren() == 0) {
if (model()->childAtIndex(selectedRow())->label() == promptMessage()) {
- if (event == Ion::Events::OK || event == Ion::Events::EXE) {
+ if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
globalPreferences->setShowPopUp(!globalPreferences->showPopUp());
m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
return true;
}
return false;
}
- if (model()->childAtIndex(selectedRow())->label() == I18n::Message::Brightness) {
- if (event == Ion::Events::Right || event == Ion::Events::Left || event == Ion::Events::Plus || event == Ion::Events::Minus) {
- int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates;
- int direction = (event == Ion::Events::Right || event == Ion::Events::Plus) ? delta : -delta;
- globalPreferences->setBrightnessLevel(globalPreferences->brightnessLevel()+direction);
- m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
- return true;
- }
- return false;
- }
if (model()->childAtIndex(selectedRow())->label() == I18n::Message::Language || model()->childAtIndex(selectedRow())->label() == I18n::Message::Country) {
if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
m_localizationController.setMode(model()->childAtIndex(selectedRow())->label() == I18n::Message::Language ? LocalizationController::Mode::Language : LocalizationController::Mode::Country);
@@ -97,12 +90,18 @@ bool MainController::handleEvent(Ion::Events::Event event) {
subController = &m_examModeController;
} else if (title == I18n::Message::About) {
subController = &m_aboutController;
+ } else if (title == I18n::Message::BrightnessSettings) {
+ subController = &m_brightnessController;
} else if (title == I18n::Message::Accessibility) {
subController = &m_accessibilityController;
} else if (title == I18n::Message::DateTime) {
subController = &m_dateTimeController;
} else if (title == I18n::Message::MathOptions) {
subController = &m_mathOptionsController;
+ } else if (title == I18n::Message::CodeApp) {
+ subController = &m_codeOptionsController;
+ } else if (title == I18n::Message::ExternalApps) {
+ subController = &m_externalController;
} else {
subController = &m_preferencesController;
}
@@ -126,11 +125,7 @@ KDCoordinate MainController::rowHeight(int j) {
}
KDCoordinate MainController::cumulatedHeightFromIndex(int j) {
- KDCoordinate height = j * rowHeight(0);
- if (j > k_indexOfBrightnessCell) {
- height += CellWithSeparator::k_margin;
- }
- return height;
+ return j * rowHeight(0);
}
int MainController::indexFromCumulatedHeight(KDCoordinate offsetY) {
@@ -147,11 +142,8 @@ HighlightCell * MainController::reusableCell(int index, int type) {
return &m_cells[index];
}
assert(index == 0);
- if (type == 2) {
- return &m_popUpCell;
- }
- assert(type == 1);
- return &m_brightnessCell;
+ assert(type == 2);
+ return &m_popUpCell;
}
int MainController::reusableCellCount(int type) {
@@ -181,7 +173,7 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) {
myGauge->setLevel((float)globalPreferences->brightnessLevel()/(float)Ion::Backlight::MaxBrightness);
return;
}
- MessageTableCell * myCell = (MessageTableCell *)cell;
+ MessageTableCell<> * myCell = (MessageTableCell<> *)cell;
myCell->setMessage(title);
if (model()->childAtIndex(index)->label() == I18n::Message::Language) {
int index = (int)(globalPreferences->language());
@@ -202,9 +194,6 @@ void MainController::willDisplayCellForIndex(HighlightCell * cell, int index) {
MessageTableCellWithChevronAndMessage * myTextCell = (MessageTableCellWithChevronAndMessage *)cell;
int childIndex = -1;
switch (model()->childAtIndex(index)->label()) {
- case I18n::Message::FontSizes:
- childIndex = GlobalPreferences::sharedGlobalPreferences()->font() == KDFont::LargeFont ? 0 : 1;
- break;
default:
break;
}
diff --git a/apps/settings/main_controller.h b/apps/settings/main_controller.h
index fd638a0cd9e..e78aff9a243 100644
--- a/apps/settings/main_controller.h
+++ b/apps/settings/main_controller.h
@@ -8,9 +8,12 @@
#include "sub_menu/accessibility_controller.h"
#include "sub_menu/datetime_controller.h"
#include "sub_menu/exam_mode_controller.h"
+#include "sub_menu/code_options_controller.h"
#include "sub_menu/localization_controller.h"
#include "sub_menu/math_options_controller.h"
#include "sub_menu/preferences_controller.h"
+#include "sub_menu/external_controller.h"
+#include "sub_menu/brightness_controller.h"
namespace Settings {
@@ -22,10 +25,15 @@ extern const Shared::SettingsMessageTree s_symbolChildren[4];
extern const Shared::SettingsMessageTree s_symbolFunctionChildren[3];
extern const Shared::SettingsMessageTree s_modelMathOptionsChildren[6];
extern const Shared::SettingsMessageTree s_modelFontChildren[2];
+extern const Shared::SettingsMessageTree s_codeChildren[3];
extern const Shared::SettingsMessageTree s_modelDateTimeChildren[3];
extern const Shared::SettingsMessageTree s_accessibilityChildren[6];
-extern const Shared::SettingsMessageTree s_contributorsChildren[23];
-extern const Shared::SettingsMessageTree s_modelAboutChildren[8];
+extern const Shared::SettingsMessageTree s_contributorsChildren[18];
+extern const Shared::SettingsMessageTree s_modelAboutChildren[10];
+extern const Shared::SettingsMessageTree s_usbProtectionChildren[2];
+extern const Shared::SettingsMessageTree s_usbProtectionLevelChildren[3];
+extern const Shared::SettingsMessageTree s_externalChildren[2];
+extern const Shared::SettingsMessageTree s_brightnessChildren[4];
extern const Shared::SettingsMessageTree s_model;
class MainController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource {
@@ -61,18 +69,20 @@ class MainController : public ViewController, public ListViewDataSource, public
StackViewController * stackController() const;
I18n::Message promptMessage() const;
bool hasPrompt() const { return promptMessage() != I18n::Message::Default; }
- constexpr static int k_numberOfSimpleChevronCells = 9;
+ constexpr static int k_numberOfSimpleChevronCells = 10;
MessageTableCellWithChevronAndMessage m_cells[k_numberOfSimpleChevronCells];
- MessageTableCellWithGaugeWithSeparator m_brightnessCell;
MessageTableCellWithSwitch m_popUpCell;
SelectableTableView m_selectableTableView;
MathOptionsController m_mathOptionsController;
+ BrightnessController m_brightnessController;
LocalizationController m_localizationController;
AccessibilityController m_accessibilityController;
DateTimeController m_dateTimeController;
+ CodeOptionsController m_codeOptionsController;
ExamModeController m_examModeController;
AboutController m_aboutController;
PreferencesController m_preferencesController;
+ ExternalController m_externalController;
};
}
diff --git a/apps/settings/main_controller_prompt_beta.cpp b/apps/settings/main_controller_prompt_beta.cpp
index b462cc14b3a..0f48e7940ed 100644
--- a/apps/settings/main_controller_prompt_beta.cpp
+++ b/apps/settings/main_controller_prompt_beta.cpp
@@ -8,15 +8,18 @@ namespace Settings {
constexpr SettingsMessageTree s_modelMenu[] =
{SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren),
- SettingsMessageTree(I18n::Message::Brightness),
+ SettingsMessageTree(I18n::Message::BrightnessSettings, s_brightnessChildren),
SettingsMessageTree(I18n::Message::DateTime, s_modelDateTimeChildren),
- SettingsMessageTree(I18n::Message::FontSizes, s_modelFontChildren),
SettingsMessageTree(I18n::Message::Language),
SettingsMessageTree(I18n::Message::Country),
SettingsMessageTree(I18n::Message::ExamMode, ExamModeConfiguration::s_modelExamChildren),
+#ifdef HAS_CODE
+ SettingsMessageTree(I18n::Message::CodeApp, s_codeChildren),
+#endif
SettingsMessageTree(I18n::Message::BetaPopUp),
- SettingsMessageTree(I18n::Message::About, s_modelAboutChildren),
- SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren)};
+ SettingsMessageTree(I18n::Message::ExternalApps, s_externalChildren),
+ SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren),
+ SettingsMessageTree(I18n::Message::About, s_modelAboutChildren)};
constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu);
diff --git a/apps/settings/main_controller_prompt_none.cpp b/apps/settings/main_controller_prompt_none.cpp
index 965fffe0706..46511e36091 100644
--- a/apps/settings/main_controller_prompt_none.cpp
+++ b/apps/settings/main_controller_prompt_none.cpp
@@ -1,21 +1,26 @@
-#include "main_controller.h"
-#include "../exam_mode_configuration.h"
#include
+#include "../exam_mode_configuration.h"
+#include "main_controller.h"
+
using namespace Shared;
namespace Settings {
constexpr SettingsMessageTree s_modelMenu[] =
{SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren),
- SettingsMessageTree(I18n::Message::Brightness),
- SettingsMessageTree(I18n::Message::DateTime, s_modelDateTimeChildren),
- SettingsMessageTree(I18n::Message::Language),
- SettingsMessageTree(I18n::Message::Country),
- SettingsMessageTree(I18n::Message::ExamMode, ExamModeConfiguration::s_modelExamChildren),
- SettingsMessageTree(I18n::Message::FontSizes, s_modelFontChildren),
- SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren),
- SettingsMessageTree(I18n::Message::About, s_modelAboutChildren)};
+ SettingsMessageTree(I18n::Message::BrightnessSettings, s_brightnessChildren),
+ SettingsMessageTree(I18n::Message::DateTime, s_modelDateTimeChildren),
+ SettingsMessageTree(I18n::Message::Language),
+ SettingsMessageTree(I18n::Message::Country),
+ SettingsMessageTree(I18n::Message::ExamMode, ExamModeConfiguration::s_modelExamChildren),
+#ifdef HAS_CODE
+ SettingsMessageTree(I18n::Message::CodeApp, s_codeChildren),
+#endif
+ //SettingsMessageTree(I18n::Message::UsbSetting, s_usbProtectionChildren),
+ SettingsMessageTree(I18n::Message::ExternalApps, s_externalChildren),
+ SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren),
+ SettingsMessageTree(I18n::Message::About, s_modelAboutChildren)};
constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu);
diff --git a/apps/settings/main_controller_prompt_update.cpp b/apps/settings/main_controller_prompt_update.cpp
index 3c74faffc1a..2deed3c3e8c 100644
--- a/apps/settings/main_controller_prompt_update.cpp
+++ b/apps/settings/main_controller_prompt_update.cpp
@@ -8,14 +8,17 @@ using namespace Shared;
constexpr SettingsMessageTree s_modelMenu[] =
{SettingsMessageTree(I18n::Message::MathOptions, s_modelMathOptionsChildren),
- SettingsMessageTree(I18n::Message::Brightness),
+ SettingsMessageTree(I18n::Message::BrightnessSettings, s_brightnessChildren),
SettingsMessageTree(I18n::Message::DateTime, s_modelDateTimeChildren),
- SettingsMessageTree(I18n::Message::FontSizes, s_modelFontChildren),
SettingsMessageTree(I18n::Message::Language),
SettingsMessageTree(I18n::Message::Country),
SettingsMessageTree(I18n::Message::ExamMode, ExamModeConfiguration::s_modelExamChildren),
+#ifdef HAS_CODE
+ SettingsMessageTree(I18n::Message::CodeApp, s_codeChildren),
+#endif
SettingsMessageTree(I18n::Message::UpdatePopUp),
SettingsMessageTree(I18n::Message::Accessibility, s_accessibilityChildren),
+ SettingsMessageTree(I18n::Message::ExternalApps, s_externalChildren),
SettingsMessageTree(I18n::Message::About, s_modelAboutChildren)};
constexpr SettingsMessageTree s_model = SettingsMessageTree(I18n::Message::SettingsApp, s_modelMenu);
diff --git a/apps/settings/sub_menu/about_controller.cpp b/apps/settings/sub_menu/about_controller.cpp
index 220a2c39647..dcae3211a61 100644
--- a/apps/settings/sub_menu/about_controller.cpp
+++ b/apps/settings/sub_menu/about_controller.cpp
@@ -1,11 +1,15 @@
#include "about_controller.h"
#include "../../../python/src/py/mpconfig.h"
+#include "poincare/division.h"
#include
#include
#include
#include
+#include
#include
+#include
+
#define MP_STRINGIFY_HELPER(x) #x
#define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x)
@@ -13,6 +17,8 @@
#error This file expects OMEGA_STATE to be defined
#endif
+
+using namespace Shared;
namespace Settings {
AboutController::AboutController(Responder * parentResponder) :
@@ -21,7 +27,7 @@ AboutController::AboutController(Responder * parentResponder) :
m_contributorsCell(KDFont::LargeFont, KDFont::SmallFont)
//m_view(&m_selectableTableView)
{
- for (int i = 0; i < k_totalNumberOfCell; i++) {
+ for (int i = 0; i < k_totalNumberOfCell - 1; i++) {
m_cells[i].setMessageFont(KDFont::LargeFont);
m_cells[i].setAccessoryFont(KDFont::SmallFont);
m_cells[i].setAccessoryTextColor(Palette::SecondaryText);
@@ -32,7 +38,7 @@ bool AboutController::handleEvent(Ion::Events::Event event) {
I18n::Message childLabel = m_messageTreeModel->childAtIndex(selectedRow()+(!hasUsernameCell()))->label();
/* We hide here the activation hardware test app: in the menu "about", by
* clicking on '6' on the last row. */
- if ((event == Ion::Events::Six || event == Ion::Events::LowerT || event == Ion::Events::UpperT) && childLabel == I18n::Message::FccId) {
+ if ((event == Ion::Events::Six || event == Ion::Events::LowerT || event == Ion::Events::UpperT) && childLabel == I18n::Message::FccId && !GlobalPreferences::sharedGlobalPreferences()->isInExamMode()) {
Container::activeApp()->displayModalViewController(&m_hardwareTestPopUpController, 0.f, 0.f, Metric::ExamPopUpTopMargin, Metric::PopUpRightMargin, Metric::ExamPopUpBottomMargin, Metric::PopUpLeftMargin);
return true;
}
@@ -59,6 +65,15 @@ bool AboutController::handleEvent(Ion::Events::Event event) {
}
return true;
}
+ if (childLabel == I18n::Message::UpsilonVersion) {
+ MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)m_selectableTableView.selectedCell();
+ if (strcmp(myCell->accessoryText(), Ion::upsilonVersion()) == 0) {
+ myCell->setAccessoryText(MP_STRINGIFY(OMEGA_STATE)); //Change for public/dev
+ return true;
+ }
+ myCell->setAccessoryText(Ion::upsilonVersion());
+ return true;
+ }
if (childLabel == I18n::Message::OmegaVersion) {
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)m_selectableTableView.selectedCell();
if (strcmp(myCell->accessoryText(), Ion::omegaVersion()) == 0) {
@@ -95,6 +110,32 @@ bool AboutController::handleEvent(Ion::Events::Event event) {
return true;
}
+ if(childLabel == I18n::Message::Battery){
+ MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)m_selectableTableView.selectedCell();
+ char batteryLevel[5];
+ if(strchr(myCell->accessoryText(), '%') == NULL) {
+ float voltage = (Ion::Battery::voltage() - 3.6) * 166;
+ if(voltage < 0.0) {
+ myCell->setAccessoryText("1%"); // We cheat...
+ return true;
+ } else if (voltage >= 100.0) {
+ myCell->setAccessoryText("100%");
+ return true;
+ } else {
+ int batteryLen = Poincare::Integer((int) voltage).serialize(batteryLevel, 5);
+ batteryLevel[batteryLen] = '%';
+ batteryLevel[batteryLen+1] = '\0';
+ }
+ }
+ else {
+ int batteryLen = Poincare::Number::FloatNumber(Ion::Battery::voltage()).serialize(batteryLevel, 5, Poincare::Preferences::PrintFloatMode::Decimal, 3);
+ batteryLevel[batteryLen] = 'V';
+ batteryLevel[batteryLen+1] = '\0';
+ }
+
+ myCell->setAccessoryText(batteryLevel);
+ return true;
+ }
}
return false;
}
@@ -108,8 +149,8 @@ int AboutController::numberOfRows() const {
HighlightCell * AboutController::reusableCell(int index, int type) {
assert(index >= 0);
if (type == 0) {
- assert(index < k_totalNumberOfCell-1-(!hasUsernameCell()));
- return &m_cells[index+(!hasUsernameCell())];
+ assert(index < k_totalNumberOfCell-1);
+ return &m_cells[index];
}
assert(index == 0);
return &m_contributorsCell;
@@ -122,7 +163,7 @@ int AboutController::typeAtLocation(int i, int j) {
int AboutController::reusableCellCount(int type) {
switch (type) {
case 0:
- return k_totalNumberOfCell-1-(!hasUsernameCell());
+ return k_totalNumberOfCell-1;
case 1:
return 1;
default:
@@ -138,7 +179,6 @@ bool AboutController::hasUsernameCell() const {
void AboutController::willDisplayCellForIndex(HighlightCell * cell, int index) {
int i = index + (!hasUsernameCell());
GenericSubController::willDisplayCellForIndex(cell, i);
- assert(index >= 0 && index < k_totalNumberOfCell);
if (m_messageTreeModel->childAtIndex(i)->label() == I18n::Message::Contributors) {
MessageTableCellWithChevronAndMessage * myTextCell = (MessageTableCellWithChevronAndMessage *)cell;
myTextCell->setSubtitle(I18n::Message::Default);
@@ -148,22 +188,30 @@ void AboutController::willDisplayCellForIndex(HighlightCell * cell, int index) {
memUseBuffer[len] = 'k';
memUseBuffer[len+1] = 'B';
memUseBuffer[len+2] = '/';
-
+
len = Poincare::Integer((int)((float) Ion::Storage::k_storageSize / 1024.f)).serialize(memUseBuffer + len + 3, 4) + len + 3;
memUseBuffer[len] = 'k';
memUseBuffer[len+1] = 'B';
memUseBuffer[len+2] = '\0';
-
+
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)cell;
myCell->setAccessoryText(memUseBuffer);
} else {
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)cell;
static const char * mpVersion = MICROPY_VERSION_STRING;
+
+ static char batteryLevel[5];
+ int batteryLen = Poincare::Number::FloatNumber(Ion::Battery::voltage()).serialize(batteryLevel, 5, Poincare::Preferences::PrintFloatMode::Decimal, 3);
+ batteryLevel[batteryLen] = 'V';
+ batteryLevel[batteryLen + 1] = '\0';
+
static const char * messages[] = {
(const char*) Ion::username(),
- Ion::softwareVersion(),
+ Ion::upsilonVersion(),
Ion::omegaVersion(),
+ Ion::softwareVersion(),
mpVersion,
+ batteryLevel,
"",
Ion::serialNumber(),
Ion::fccId(),
diff --git a/apps/settings/sub_menu/about_controller.h b/apps/settings/sub_menu/about_controller.h
index beef15d95cb..b661ac9e399 100644
--- a/apps/settings/sub_menu/about_controller.h
+++ b/apps/settings/sub_menu/about_controller.h
@@ -11,7 +11,6 @@ namespace Settings {
class AboutController : public GenericSubController {
public:
AboutController(Responder * parentResponder);
- //View * view() override { return &m_view; }
View * view() override { return &m_selectableTableView; }
void viewWillAppear() override;
TELEMETRY_ID("About");
@@ -26,8 +25,7 @@ class AboutController : public GenericSubController {
bool hasUsernameCell() const;
ContributorsController m_contributorsController;
MessageTableCellWithChevronAndMessage m_contributorsCell;
- //SelectableViewWithMessages m_view;
- MessageTableCellWithBuffer m_cells[k_totalNumberOfCell];
+ MessageTableCellWithBuffer m_cells[k_totalNumberOfCell - 1];
HardwareTest::PopUpController m_hardwareTestPopUpController;
};
diff --git a/apps/settings/sub_menu/about_controller_non_official.cpp b/apps/settings/sub_menu/about_controller_non_official.cpp
index 52e111eb513..cedd20636a5 100644
--- a/apps/settings/sub_menu/about_controller_non_official.cpp
+++ b/apps/settings/sub_menu/about_controller_non_official.cpp
@@ -5,7 +5,7 @@ namespace Settings {
void AboutController::viewWillAppear() {
GenericSubController::viewWillAppear();
- // IN OMEGA, THE FOLLOWING LINES ARE ADDED IN A SUBMENU "LEGAL INFORMATION", BECAUSE MESSAGES DELETE THE SCROLLBAR.
+ // IN UPSILON, THE FOLLOWING LINES ARE ADDED IN A SUBMENU "LEGAL INFORMATION", BECAUSE MESSAGES DELETE THE SCROLLBAR.
// --------------------- Please don't edit these lines ----------------------
I18n::Message cautionMessages[] = {I18n::Message::AboutWarning1, I18n::Message::AboutWarning2, I18n::Message::AboutWarning3, I18n::Message::AboutWarning4};
// m_view.setMessages(cautionMessages, sizeof(cautionMessages)/sizeof(I18n::Message));
diff --git a/apps/settings/sub_menu/accessibility_controller.cpp b/apps/settings/sub_menu/accessibility_controller.cpp
index 1df981f379d..ca6b5b4a0da 100644
--- a/apps/settings/sub_menu/accessibility_controller.cpp
+++ b/apps/settings/sub_menu/accessibility_controller.cpp
@@ -25,7 +25,7 @@ bool AccessibilityController::handleEvent(Ion::Events::Event event) {
int redGamma, greenGamma, blueGamma;
KDIonContext::sharedContext()->gamma.gamma(redGamma, greenGamma, blueGamma);
- if (event == Ion::Events::OK || event == Ion::Events::EXE) {
+ if ((event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) && (selectedRow() <= 2)) {
if (selectedRow() == 0) {
invertEnabled = !invertEnabled;
}
diff --git a/apps/settings/sub_menu/brightness_controller.cpp b/apps/settings/sub_menu/brightness_controller.cpp
new file mode 100644
index 00000000000..9af1f42155a
--- /dev/null
+++ b/apps/settings/sub_menu/brightness_controller.cpp
@@ -0,0 +1,142 @@
+#include "brightness_controller.h"
+#include "../../global_preferences.h"
+#include "../../apps_container.h"
+#include "../../shared/poincare_helpers.h"
+#include
+#include
+#include "../app.h"
+#include
+#include
+
+using namespace Poincare;
+using namespace Shared;
+
+namespace Settings {
+
+BrightnessController::BrightnessController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate) :
+ GenericSubController(parentResponder),
+ m_brightnessCell(I18n::Message::Brightness, KDFont::LargeFont),
+ m_editableCellIdleBeforeDimmingSeconds(&m_selectableTableView, inputEventHandlerDelegate, this),
+ m_editableCellIdleBeforeSuspendSeconds(&m_selectableTableView, inputEventHandlerDelegate, this),
+ m_BrightnessShortcutCell(&m_selectableTableView, inputEventHandlerDelegate, this)
+{
+ m_editableCellIdleBeforeDimmingSeconds.setMessage(I18n::Message::IdleTimeBeforeDimming);
+ m_editableCellIdleBeforeDimmingSeconds.setMessageFont(KDFont::LargeFont);
+ m_editableCellIdleBeforeSuspendSeconds.setMessage(I18n::Message::IdleTimeBeforeSuspend);
+ m_editableCellIdleBeforeSuspendSeconds.setMessageFont(KDFont::LargeFont);
+ m_BrightnessShortcutCell.setMessage(I18n::Message::BrightnessShortcut);
+ m_BrightnessShortcutCell.setMessageFont(KDFont::LargeFont);
+}
+
+HighlightCell * BrightnessController::reusableCell(int index, int type) {
+ HighlightCell * editableCell[] = {
+ &m_brightnessCell,
+ &m_editableCellIdleBeforeDimmingSeconds,
+ &m_editableCellIdleBeforeSuspendSeconds,
+ &m_BrightnessShortcutCell
+ };
+ return editableCell[index];
+}
+
+int BrightnessController::reusableCellCount(int type) {
+ switch(type) {
+ case 0:
+ case 1:
+ return k_totalNumberOfCell;
+ default:
+ assert(false);
+ return 0;
+ }
+}
+
+void BrightnessController::willDisplayCellForIndex(HighlightCell * cell, int index) {
+ if(index == 0){
+ MessageTableCellWithGauge * myGaugeCell = (MessageTableCellWithGauge *)cell;
+ GaugeView * myGauge = (GaugeView *)myGaugeCell->accessoryView();
+ myGauge->setLevel((float)GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()/(float)Ion::Backlight::MaxBrightness);
+ return;
+ } else {
+ MessageTableCellWithEditableText * myCell = (MessageTableCellWithEditableText *)cell;
+ GenericSubController::willDisplayCellForIndex(myCell, index);
+ char buffer[5];
+ int val;
+ switch(index){
+ case 1:{
+ val = GlobalPreferences::sharedGlobalPreferences()->idleBeforeDimmingSeconds();
+ break;
+ }
+ case 2:{
+ val = GlobalPreferences::sharedGlobalPreferences()->idleBeforeSuspendSeconds();
+ break;
+ }
+ case 3:{
+ val = GlobalPreferences::sharedGlobalPreferences()->brightnessShortcut();
+ break;
+ }
+ default:
+ assert(false);
+ }
+ Poincare::Integer(val).serialize(buffer, 5);
+ myCell->setAccessoryText(buffer);
+ }
+}
+
+bool BrightnessController::handleEvent(Ion::Events::Event event) {
+ if ((selectedRow() == 0) && (event == Ion::Events::Right || event == Ion::Events::Left || event == Ion::Events::Plus || event == Ion::Events::Minus)) {
+ int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates;
+ int direction = (event == Ion::Events::Right || event == Ion::Events::Plus) ? delta : -delta;
+ GlobalPreferences::sharedGlobalPreferences()->setBrightnessLevel(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()+direction);
+ m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
+ return true;
+ }
+ if (event == Ion::Events::BrightnessPlus || event == Ion::Events::BrightnessMinus){
+ int delta = Ion::Backlight::MaxBrightness/GlobalPreferences::NumberOfBrightnessStates;
+ int NumberOfStepsPerShortcut = GlobalPreferences::sharedGlobalPreferences()->brightnessShortcut();
+ int direction = (event == Ion::Events::BrightnessPlus) ? NumberOfStepsPerShortcut*delta : -delta*NumberOfStepsPerShortcut;
+ GlobalPreferences::sharedGlobalPreferences()->setBrightnessLevel(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel()+direction);
+ m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), 0);
+ return true;
+ }
+ return false;
+}
+
+bool BrightnessController::textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) {
+ return ((event == Ion::Events::Up && selectedRow() > 0) || (event == Ion::Events::Down && selectedRow() < k_totalNumberOfCell - 1))
+ || TextFieldDelegate::textFieldShouldFinishEditing(textField, event);
+}
+
+bool BrightnessController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
+ double floatBody;
+ if (textFieldDelegateApp()->hasUndefinedValue(text, floatBody)) {
+ return false;
+ }
+ int val = std::round(floatBody);
+ switch (selectedRow()) {
+ case 1:
+ GlobalPreferences::sharedGlobalPreferences()->setIdleBeforeDimmingSeconds(val);
+ m_editableCellIdleBeforeDimmingSeconds.setAccessoryText(text);
+ break;
+ case 2:
+ GlobalPreferences::sharedGlobalPreferences()->setIdleBeforeSuspendSeconds(val);
+ m_editableCellIdleBeforeSuspendSeconds.setAccessoryText(text);
+ break;
+ case 3:{
+ if(val > GlobalPreferences::NumberOfBrightnessStates){ val = GlobalPreferences::NumberOfBrightnessStates;
+ } else if (val < 0){val = 0;}
+ GlobalPreferences::sharedGlobalPreferences()->setBrightnessShortcut(val);
+ m_BrightnessShortcutCell.setAccessoryText(text);
+ break;
+ }
+ default:
+ assert(false);
+ }
+ AppsContainer * myContainer = AppsContainer::sharedAppsContainer();
+ myContainer->refreshPreferences();
+ m_selectableTableView.reloadCellAtLocation(0, selectedRow());
+ if (event == Ion::Events::Up || event == Ion::Events::Down || event == Ion::Events::OK) {
+ m_selectableTableView.handleEvent(event);
+ }
+ return true;
+}
+
+}
diff --git a/apps/settings/sub_menu/brightness_controller.h b/apps/settings/sub_menu/brightness_controller.h
new file mode 100644
index 00000000000..a36a39a3246
--- /dev/null
+++ b/apps/settings/sub_menu/brightness_controller.h
@@ -0,0 +1,33 @@
+#ifndef SETTINGS_BRIGHTNESS_CONTROLLER_H
+#define SETTINGS_BRIGHTNESS_CONTROLLER_H
+
+#include "generic_sub_controller.h"
+#include "preferences_controller.h"
+#include "../message_table_cell_with_editable_text_with_separator.h"
+#include "../../shared/parameter_text_field_delegate.h"
+#include "../message_table_cell_with_gauge_with_separator.h"
+
+namespace Settings {
+
+class BrightnessController : public GenericSubController, public Shared::ParameterTextFieldDelegate {
+public:
+ BrightnessController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate);
+ TELEMETRY_ID("BrightnessSettings");
+ HighlightCell * reusableCell(int index, int type) override;
+ int reusableCellCount(int type) override;
+ void willDisplayCellForIndex(HighlightCell * cell, int index) override;
+ bool handleEvent(Ion::Events::Event event) override;
+ bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
+ bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
+protected:
+ constexpr static int k_totalNumberOfCell = 4;
+private:
+ MessageTableCellWithGauge m_brightnessCell;
+ MessageTableCellWithEditableText m_editableCellIdleBeforeDimmingSeconds;
+ MessageTableCellWithEditableText m_editableCellIdleBeforeSuspendSeconds;
+ MessageTableCellWithEditableText m_BrightnessShortcutCell;
+};
+
+}
+
+#endif
diff --git a/apps/settings/sub_menu/code_options_controller.cpp b/apps/settings/sub_menu/code_options_controller.cpp
new file mode 100644
index 00000000000..ae7d5bbc2a2
--- /dev/null
+++ b/apps/settings/sub_menu/code_options_controller.cpp
@@ -0,0 +1,85 @@
+#include "code_options_controller.h"
+#include
+#include "../../global_preferences.h"
+
+using namespace Shared;
+
+namespace Settings {
+
+CodeOptionsController::CodeOptionsController(Responder * parentResponder) :
+ GenericSubController(parentResponder),
+ m_preferencesController(this)
+{
+ m_chevronCellFontSize.setMessageFont(KDFont::LargeFont);
+ m_switchCellAutoCompletion.setMessageFont(KDFont::LargeFont);
+ m_switchCellSyntaxHighlighting.setMessageFont(KDFont::LargeFont);
+}
+
+bool CodeOptionsController::handleEvent(Ion::Events::Event event) {
+ if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
+ switch (selectedRow()){
+ case 1:
+ GlobalPreferences::sharedGlobalPreferences()->setAutocomplete(!GlobalPreferences::sharedGlobalPreferences()->autocomplete());
+ m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
+ break;
+ case 2:
+ GlobalPreferences::sharedGlobalPreferences()->setSyntaxhighlighting(!GlobalPreferences::sharedGlobalPreferences()->syntaxhighlighting());
+ m_selectableTableView.reloadCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
+ break;
+ default:
+ GenericSubController * subController = nullptr;
+ subController = &m_preferencesController;
+ subController->setMessageTreeModel(m_messageTreeModel->childAtIndex(selectedRow()));
+ StackViewController * stack = stackController();
+ m_lastSelect = selectedRow();
+ stack->push(subController);
+ break;
+ }
+ return true;
+ }
+ return GenericSubController::handleEvent(event);
+}
+
+HighlightCell * CodeOptionsController::reusableCell(int index, int type) {
+ assert(type == 0);
+ assert(index >= 0 && index < k_totalNumberOfCell);
+ if (index == 0) {
+ return &m_chevronCellFontSize;
+ }
+ else if (index == 1) {
+ return &m_switchCellAutoCompletion;
+ }
+ return &m_switchCellSyntaxHighlighting;
+}
+
+int CodeOptionsController::reusableCellCount(int type) {
+ assert(type == 0);
+ return k_totalNumberOfCell;
+}
+
+void CodeOptionsController::willDisplayCellForIndex(HighlightCell * cell, int index) {
+ GenericSubController::willDisplayCellForIndex(cell, index);
+ I18n::Message thisLabel = m_messageTreeModel->childAtIndex(index)->label();
+
+ if (thisLabel == I18n::Message::FontSizes){
+ MessageTableCellWithChevronAndMessage * myTextCell = (MessageTableCellWithChevronAndMessage *)cell;
+ myTextCell->setMessage(thisLabel);
+ GlobalPreferences::sharedGlobalPreferences()->font() == KDFont::LargeFont
+ ? myTextCell->setSubtitle(I18n::Message::LargeFont)
+ : myTextCell->setSubtitle(I18n::Message::SmallFont);
+ }
+#ifdef HAS_CODE
+ else if (thisLabel == I18n::Message::Autocomplete) {
+ MessageTableCellWithSwitch * mySwitchCell = (MessageTableCellWithSwitch *)cell;
+ SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView();
+ mySwitch->setState(GlobalPreferences::sharedGlobalPreferences()->autocomplete());
+ }
+ else if (thisLabel == I18n::Message::SyntaxHighlighting) {
+ MessageTableCellWithSwitch * mySwitchCell = (MessageTableCellWithSwitch *)cell;
+ SwitchView * mySwitch = (SwitchView *)mySwitchCell->accessoryView();
+ mySwitch->setState(GlobalPreferences::sharedGlobalPreferences()->syntaxhighlighting());
+ }
+#endif
+}
+
+}
diff --git a/apps/settings/sub_menu/code_options_controller.h b/apps/settings/sub_menu/code_options_controller.h
new file mode 100644
index 00000000000..5f9b6acea22
--- /dev/null
+++ b/apps/settings/sub_menu/code_options_controller.h
@@ -0,0 +1,26 @@
+#ifndef SETTINGS_CODE_OPTIONS_CONTROLLER_H
+#define SETTINGS_CODE_OPTIONS_CONTROLLER_H
+
+#include "generic_sub_controller.h"
+#include "preferences_controller.h"
+
+namespace Settings {
+
+class CodeOptionsController : public GenericSubController {
+public:
+ CodeOptionsController(Responder * parentResponder);
+ bool handleEvent(Ion::Events::Event event) override;
+ HighlightCell * reusableCell(int index, int type) override;
+ int reusableCellCount(int type) override;
+ void willDisplayCellForIndex(HighlightCell * cell, int index) override;
+private:
+ constexpr static int k_totalNumberOfCell = 4;
+ PreferencesController m_preferencesController;
+ MessageTableCellWithChevronAndMessage m_chevronCellFontSize;
+ MessageTableCellWithSwitch m_switchCellAutoCompletion;
+ MessageTableCellWithSwitch m_switchCellSyntaxHighlighting;
+};
+
+}
+
+#endif
diff --git a/apps/settings/sub_menu/contributors_controller.cpp b/apps/settings/sub_menu/contributors_controller.cpp
index 26bab3326a5..378bfc3f6c1 100644
--- a/apps/settings/sub_menu/contributors_controller.cpp
+++ b/apps/settings/sub_menu/contributors_controller.cpp
@@ -28,8 +28,14 @@ int ContributorsController::reusableCellCount(int type) {
return k_totalNumberOfCell;
}
-constexpr static int s_numberOfDevelopers = 13;
+constexpr static int s_numberOfDevelopers = 18;
+constexpr static int s_numberOfUpsilonDevelopers = 5;
constexpr static I18n::Message s_developersUsernames[s_numberOfDevelopers] = {
+ I18n::Message::PLaurianFournier,
+ I18n::Message::PYannCouturier,
+ I18n::Message::PDavidLuca,
+ I18n::Message::PLoicE,
+ I18n::Message::PVictorKretz,
I18n::Message::PQuentinGuidee,
I18n::Message::PJoachimLeFournis,
I18n::Message::PMaximeFriess,
@@ -45,32 +51,13 @@ constexpr static I18n::Message s_developersUsernames[s_numberOfDevelopers] = {
I18n::Message::PCyprienMejat,
};
-constexpr static int s_numberOfBetaTesters = 8;
-constexpr static I18n::Message s_betaTestersUsernames[s_numberOfBetaTesters] = {
- I18n::Message::PTimeoArnouts,
- I18n::Message::PJulieC,
- I18n::Message::PLelahelHideux,
- I18n::Message::PMadil,
- I18n::Message::PHilaireLeRoux,
- I18n::Message::PHectorNussbaumer,
- I18n::Message::PRaphaelDyda,
- I18n::Message::PThibautC,
-};
-
void ContributorsController::willDisplayCellForIndex(HighlightCell * cell, int index) {
MessageTableCellWithBuffer * myTextCell = (MessageTableCellWithBuffer *)cell;
- if (index == 0) {
- myTextCell->setAccessoryText("");
- myTextCell->setTextColor(KDColor::RGB24(0xC03535));
- } else if (index > 0 && index <= s_numberOfDevelopers) {
- myTextCell->setAccessoryText(I18n::translate(s_developersUsernames[index - 1]));
- myTextCell->setTextColor(Palette::PrimaryText);
- } else if (index == s_numberOfDevelopers + 1) {
- myTextCell->setAccessoryText("");
- myTextCell->setTextColor(KDColor::RGB24(0x1ABC9A));
+ myTextCell->setAccessoryText(I18n::translate(s_developersUsernames[index]));
+ if (index < s_numberOfUpsilonDevelopers) {
+ myTextCell->setTextColor(KDColor::RGB24(0x5e81ac));
} else {
- myTextCell->setAccessoryText(I18n::translate(s_betaTestersUsernames[index - 2 - s_numberOfDevelopers]));
- myTextCell->setTextColor(Palette::PrimaryText);
+ myTextCell->setTextColor(KDColor::RGB24(0xc53431));
}
myTextCell->setAccessoryTextColor(Palette::SecondaryText);
GenericSubController::willDisplayCellForIndex(cell, index);
diff --git a/apps/settings/sub_menu/datetime_controller.cpp b/apps/settings/sub_menu/datetime_controller.cpp
index f3ca0576049..35fb8c99455 100644
--- a/apps/settings/sub_menu/datetime_controller.cpp
+++ b/apps/settings/sub_menu/datetime_controller.cpp
@@ -26,11 +26,14 @@ DateTimeController::DateTimeController(Responder * parentResponder) :
bool DateTimeController::handleEvent(Ion::Events::Event event) {
bool clockEnabled = Ion::RTC::mode() != Ion::RTC::Mode::Disabled;
- if (event == Ion::Events::OK || event == Ion::Events::EXE) {
+ if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
if (selectedRow() == 0) {
clockEnabled = !clockEnabled;
if (clockEnabled) {
+ #ifndef _FXCG
+ // This doesn't apply on Casio calculators
Container::activeApp()->displayWarning(I18n::Message::RTCWarning1, I18n::Message::RTCWarning2);
+ #endif
}
Ion::RTC::setMode(clockEnabled ? Ion::RTC::Mode::HSE : Ion::RTC::Mode::Disabled);
}
diff --git a/apps/settings/sub_menu/exam_mode_controller.cpp b/apps/settings/sub_menu/exam_mode_controller.cpp
index 33a853eaab1..9fd322321a7 100644
--- a/apps/settings/sub_menu/exam_mode_controller.cpp
+++ b/apps/settings/sub_menu/exam_mode_controller.cpp
@@ -88,7 +88,7 @@ void ExamModeController::willDisplayCellForIndex(HighlightCell * cell, int index
I18n::Message thisLabel = m_messageTreeModel->childAtIndex(index)->label();
if (GlobalPreferences::sharedGlobalPreferences()->isInExamMode() && (thisLabel == I18n::Message::ActivateExamMode || thisLabel == I18n::Message::ExamModeActive)) {
- MessageTableCell * myCell = (MessageTableCell *)cell;
+ MessageTableCell<> * myCell = (MessageTableCell<> *)cell;
myCell->setMessage(I18n::Message::ExamModeActive);
}
if (thisLabel == I18n::Message::ExamModeMode) {
diff --git a/apps/settings/sub_menu/exam_mode_controller.h b/apps/settings/sub_menu/exam_mode_controller.h
index e7abb1b1298..ebdfb219536 100644
--- a/apps/settings/sub_menu/exam_mode_controller.h
+++ b/apps/settings/sub_menu/exam_mode_controller.h
@@ -27,7 +27,7 @@ class ExamModeController : public GenericSubController {
GlobalPreferences::ExamMode examMode();
static constexpr int k_maxNumberOfCells = 4;
SelectableViewWithMessages m_contentView;
- MessageTableCell m_cell[k_maxNumberOfCells];
+ MessageTableCell<> m_cell[k_maxNumberOfCells];
PreferencesController m_ledController;
PreferencesController m_examModeModeController;
MessageTableCellWithChevronAndMessage m_examModeCell;
diff --git a/apps/settings/sub_menu/external_controller.cpp b/apps/settings/sub_menu/external_controller.cpp
new file mode 100644
index 00000000000..4ba28901f70
--- /dev/null
+++ b/apps/settings/sub_menu/external_controller.cpp
@@ -0,0 +1,72 @@
+#include "external_controller.h"
+
+#include
+#include
+#include
+#include
+#include
+#include "../../apps_container.h"
+#include "../../global_preferences.h"
+
+using namespace Poincare;
+using namespace Shared;
+
+namespace Settings {
+
+ExternalController::ExternalController(Responder *parentResponder):
+ GenericSubController(parentResponder),
+ m_contentView(&m_selectableTableView)
+{
+ m_writeSwitchCell.setMessageFont(KDFont::LargeFont);
+ m_enabledSwitchCell.setMessageFont(KDFont::LargeFont);
+}
+
+bool ExternalController::handleEvent(Ion::Events::Event event) {
+ if ((Ion::Events::OK == event || Ion::Events::EXE == event || Ion::Events::Right == event) && selectedRow() == 0) {
+ bool externalWasUnlocked = GlobalPreferences::sharedGlobalPreferences()->externalAppWritePermission();
+ GlobalPreferences::sharedGlobalPreferences()->setExternalAppWritePermission(!externalWasUnlocked);
+ m_selectableTableView.reloadCellAtLocation(0, selectedRow());
+ return true;
+ } else if ((Ion::Events::OK == event || Ion::Events::EXE == event || Ion::Events::Right == event) && selectedRow() == 1) {
+ bool extappWasShowed = GlobalPreferences::sharedGlobalPreferences()->externalAppShown();
+ GlobalPreferences::sharedGlobalPreferences()->setExternalAppShown(!extappWasShowed);
+ m_selectableTableView.reloadCellAtLocation(0, selectedRow());
+ return true;
+ }
+
+ return GenericSubController::handleEvent(event);
+}
+
+HighlightCell *ExternalController::reusableCell(int index, int type) {
+ if (index == 0) {
+ return &m_writeSwitchCell;
+ }
+ assert(index == 1);
+ return &m_enabledSwitchCell;
+}
+
+int ExternalController::reusableCellCount(int type) {
+ assert(type == 0);
+ return 2;
+}
+
+void ExternalController::willDisplayCellForIndex(HighlightCell *cell, int index) {
+ GenericSubController::willDisplayCellForIndex(cell, index);
+
+ if (index == 0) {
+ MessageTableCellWithSwitch *myCell = (MessageTableCellWithSwitch *)cell;
+ SwitchView *mySwitch = (SwitchView *)myCell->accessoryView();
+ mySwitch->setState(GlobalPreferences::sharedGlobalPreferences()->externalAppWritePermission());
+ } else if (index == 1) {
+ MessageTableCellWithSwitch *myCell = (MessageTableCellWithSwitch *)cell;
+ SwitchView *mySwitch = (SwitchView *)myCell->accessoryView();
+ mySwitch->setState(GlobalPreferences::sharedGlobalPreferences()->externalAppShown());
+ }
+}
+
+void ExternalController::didEnterResponderChain(Responder *previousFirstResponder) {
+ m_contentView.reload();
+ I18n::Message infoMessages[] = {I18n::Message::ExtAppWriteExplanation1, I18n::Message::ExtAppWriteExplanation2, I18n::Message::ExtAppWriteExplanation3};
+ m_contentView.setMessages(infoMessages, k_numberOfExplanationMessages);
+}
+}
diff --git a/apps/settings/sub_menu/external_controller.h b/apps/settings/sub_menu/external_controller.h
new file mode 100644
index 00000000000..11e5ac1212e
--- /dev/null
+++ b/apps/settings/sub_menu/external_controller.h
@@ -0,0 +1,29 @@
+#ifndef SETTINGS_EXTERNAL_CONTROLLER_H
+#define SETTINGS_EXTERNAL_CONTROLLER_H
+
+#include "generic_sub_controller.h"
+#include "preferences_controller.h"
+#include "selectable_view_with_messages.h"
+
+namespace Settings {
+
+class ExternalController : public GenericSubController {
+public:
+ ExternalController(Responder* parentResponder);
+ View* view() override { return &m_contentView; }
+ bool handleEvent(Ion::Events::Event event) override;
+ TELEMETRY_ID("ExternalSettings");
+ void didEnterResponderChain(Responder* previousFirstResponder) override;
+ HighlightCell* reusableCell(int index, int type) override;
+ int reusableCellCount(int type) override;
+ void willDisplayCellForIndex(HighlightCell* cell, int index) override;
+private:
+ static constexpr int k_numberOfExplanationMessages = 3;
+ SelectableViewWithMessages m_contentView;
+ MessageTableCellWithSwitch m_writeSwitchCell;
+ MessageTableCellWithSwitch m_enabledSwitchCell;
+};
+
+}
+
+#endif
diff --git a/apps/settings/sub_menu/generic_sub_controller.cpp b/apps/settings/sub_menu/generic_sub_controller.cpp
index 5286743d1d1..25c5d15fade 100644
--- a/apps/settings/sub_menu/generic_sub_controller.cpp
+++ b/apps/settings/sub_menu/generic_sub_controller.cpp
@@ -75,7 +75,7 @@ int GenericSubController::typeAtLocation(int i, int j) {
}
void GenericSubController::willDisplayCellForIndex(HighlightCell * cell, int index) {
- MessageTableCell * myCell = (MessageTableCell *)cell;
+ MessageTableCell<> * myCell = (MessageTableCell<> *)cell;
myCell->setMessage(m_messageTreeModel->childAtIndex(index)->label());
}
diff --git a/apps/settings/sub_menu/preferences_controller.cpp b/apps/settings/sub_menu/preferences_controller.cpp
index 2aba6a8691f..dbf254966cb 100644
--- a/apps/settings/sub_menu/preferences_controller.cpp
+++ b/apps/settings/sub_menu/preferences_controller.cpp
@@ -27,7 +27,7 @@ void PreferencesController::didBecomeFirstResponder() {
}
bool PreferencesController::handleEvent(Ion::Events::Event event) {
- if (event == Ion::Events::OK || event == Ion::Events::EXE) {
+ if (event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Right) {
/* Generic behaviour of preference menu*/
assert(m_messageTreeModel->label() != I18n::Message::DisplayMode || selectedRow() != numberOfRows()-1); // In that case, events OK and EXE are handled by the cell
setPreferenceWithValueIndex(m_messageTreeModel->label(), selectedRow());
diff --git a/apps/shared.de.i18n b/apps/shared.de.i18n
index 7219416911b..f4fb2d05f80 100644
--- a/apps/shared.de.i18n
+++ b/apps/shared.de.i18n
@@ -1,12 +1,8 @@
ActivateDeactivate = "Aktivieren/Deaktivieren"
-ActivateDutchExamMode = "Prüfungsmodus starten NL"
ActivateExamMode = "Prüfungsmodus starten"
ActiveExamModeMessage1 = "Alle Ihre Daten werden "
ActiveExamModeMessage2 = "gelöscht, wenn Sie den "
ActiveExamModeMessage3 = "Prüfungsmodus einschalten."
-ActiveDutchExamModeMessage1 = "Alle Daten werden gelöscht, wenn"
-ActiveDutchExamModeMessage2 = "Sie den Prüfungsmodus einschalten. "
-ActiveDutchExamModeMessage3 = "Python wird nicht verfügbar sein."
Axis = "Achse"
Cancel = "Abbrechen"
ClearColumn = "Spalte löschen"
@@ -39,7 +35,6 @@ ExitExamMode2 = "Prüfungsmodus verlassen?"
Exponential = "Exponentielle"
FillWithFormula = "Mit einer Formel füllen"
ForbiddenValue = "Verbotener Wert"
-FunctionColumn = "0(0) Spalte"
FunctionOptions = "Funktionsoptionen"
Goto = "Gehe zu"
GraphTab = "Graph"
@@ -59,7 +54,6 @@ Navigate = "Navigieren"
NEnd = "N Endwert"
Next = "Nächste"
NoDataToPlot = "Keine Daten zum Zeichnen"
-NoFunctionToDelete = "Keine Funktion zum Löschen"
NoValueToCompute = "Keine Größe zum Berechnen"
NStart = "N Startwert"
Ok = "Bestätigen"
@@ -78,7 +72,6 @@ StandardDeviation = "Standardabweichung"
Step = "Schrittwert"
StorageMemoryFull1 = "Der Speicher ist voll. Löschen Sie"
StorageMemoryFull2 = "einige Daten, dann erneut versuchen."
-StoreExpressionNotAllowed = "'store' ist verboten"
SyntaxError = "Syntaxfehler"
Sym = "sym"
TEnd = "T Endwert"
@@ -91,11 +84,40 @@ ValuesTab = "Tabelle"
Warning = "Achtung"
XEnd = "X Endwert"
XStart = "X Startwert"
-Zoom = "Zoom"
-Developers = "Entwickler"
-BetaTesters = "Beta-Tester"
ExamModeMode = "Modus"
ExamModeModeStandard = "Standard "
ExamModeModeNoSym = "Kein Symbol "
ExamModeModeNoSymNoText = "Kein Symbol kein Text "
ExamModeModeDutch = "Niederländisch "
+ColorRed = "Rot "
+ColorBlue = "Blau "
+ColorGreen = "Grün "
+ColorYellow = "Gelb "
+ColorPurple = "Violett "
+ColorCyan = "Cyan "
+ColorPink = "Rosa "
+ColorOrange = "Orange "
+TimeDimension = "Zeit"
+DistanceDimension = "Distanz"
+MassDimension = "Masse"
+CurrentDimension = "Betrieb"
+TemperatureDimension = "Temperatur"
+AmountOfSubstanceDimension = "Quantität der Materie"
+LuminousIntensityDimension = "Lichtintensität"
+FrequencyDimension = "Frequenz"
+ForceDimension = "Stärke"
+PressureDimension = "Druck"
+EnergyDimension = "Energie"
+PowerDimension = "Mächtig"
+ElectricChargeDimension = "Elektrische Ladung"
+ElectricPotentialDimension = "Elektrisches Potenzial"
+ElectricCapacitanceDimension = "Elektrische Kapazität"
+ElectricResistanceDimension = "Elektrischer Wiederstand"
+ElectricConductanceDimension = "elektrische Leitfähigkeit"
+MagneticFluxDimension = "magnetischer Fluss"
+MagneticFieldDimension = "Magnetfeld"
+InductanceDimension = "Induktivität"
+CatalyticActivityDimension = "Katalytische Aktivität"
+SurfaceDimension = "Auftauchen"
+VolumeDimension = "Volumen"
+SpeedDimension = "Geschwindigkeit"
diff --git a/apps/shared.en.i18n b/apps/shared.en.i18n
index d61df44e108..a5f65b59495 100644
--- a/apps/shared.en.i18n
+++ b/apps/shared.en.i18n
@@ -1,12 +1,8 @@
ActivateDeactivate = "Turn on/off"
ActivateExamMode = "Activate exam mode"
-ActivateDutchExamMode = "Activate Dutch exam mode"
ActiveExamModeMessage1 = "All your data will be "
ActiveExamModeMessage2 = "deleted when you activate "
ActiveExamModeMessage3 = "the exam mode."
-ActiveDutchExamModeMessage1 = "All your data will be deleted when"
-ActiveDutchExamModeMessage2 = "you activate the exam mode. Python"
-ActiveDutchExamModeMessage3 = "application will be unavailable."
Axis = "Axes"
Cancel = "Cancel"
ClearColumn = "Clear column"
@@ -39,7 +35,6 @@ ExitExamMode2 = "mode?"
Exponential = "Exponential"
FillWithFormula = "Fill with a formula"
ForbiddenValue = "Forbidden value"
-FunctionColumn = "0(0) column"
FunctionOptions = "Function options"
Goto = "Go to"
GraphTab = "Graph"
@@ -58,7 +53,6 @@ NameTooLong = "This name is too long"
Navigate = "Navigate"
Next = "Next"
NoDataToPlot = "No data to draw"
-NoFunctionToDelete = "No function to delete"
NoValueToCompute = "No values to calculate"
NEnd = "N end"
NStart = "N start"
@@ -74,7 +68,6 @@ SortValues = "Sort by increasing values"
SortSizes = "Sort by increasing frequencies"
SquareSum = "Sum of squares"
StandardDeviation = "Standard deviation"
-StoreExpressionNotAllowed = "'store' is not allowed"
StatTab = "Stats"
Step = "Step"
StorageMemoryFull1 = "The memory is full."
@@ -91,11 +84,40 @@ ValuesTab = "Table"
Warning = "Warning"
XEnd = "X end"
XStart = "X start"
-Zoom = "Zoom"
-Developers = "Developers"
-BetaTesters = "Beta testers"
ExamModeMode = "Mode"
ExamModeModeStandard = "Standard "
ExamModeModeNoSym = "No sym "
ExamModeModeNoSymNoText = "No sym no text "
ExamModeModeDutch = "Dutch "
+ColorRed = "Red "
+ColorBlue = "Blue "
+ColorGreen = "Green "
+ColorYellow = "Yellow "
+ColorPurple = "Purple "
+ColorCyan = "Cyan "
+ColorPink = "Pink "
+ColorOrange = "Orange "
+TimeDimension = "Time"
+DistanceDimension = "Distance"
+MassDimension = "Mass"
+CurrentDimension = "Running"
+TemperatureDimension = "Temperature"
+AmountOfSubstanceDimension = "Quantity of matter"
+LuminousIntensityDimension = "Light intensity"
+FrequencyDimension = "Frequency"
+ForceDimension = "Strength"
+PressureDimension = "Pressure"
+EnergyDimension = "Energy"
+PowerDimension = "Powerful"
+ElectricChargeDimension = "Electrical charge"
+ElectricPotentialDimension = "Electric potential"
+ElectricCapacitanceDimension = "Electrical capacity"
+ElectricResistanceDimension = "Electrical resistance"
+ElectricConductanceDimension = "electrical conductance"
+MagneticFluxDimension = "magnetic flux"
+MagneticFieldDimension = "Magnetic field"
+InductanceDimension = "Inductance"
+CatalyticActivityDimension = "Catalytic activity"
+SurfaceDimension = "Surface"
+VolumeDimension = "Volume"
+SpeedDimension = "Speed"
diff --git a/apps/shared.es.i18n b/apps/shared.es.i18n
index e542571edab..cc76ce7e0c1 100644
--- a/apps/shared.es.i18n
+++ b/apps/shared.es.i18n
@@ -1,12 +1,8 @@
ActivateDeactivate = "Activar/Desactivar"
ActivateExamMode = "Activar el modo examen"
-ActivateDutchExamMode = "Activar el modo examen NL"
ActiveExamModeMessage1 = "Todos sus datos se "
ActiveExamModeMessage2 = "eliminaran al activar "
ActiveExamModeMessage3 = "el modo examen."
-ActiveDutchExamModeMessage1 = "Todos sus datos se eliminaran al"
-ActiveDutchExamModeMessage2 = "activar el modo examen. La aplicación"
-ActiveDutchExamModeMessage3 = "Python ya no estará disponible."
Axis = "Ejes"
Cancel = "Cancelar"
ClearColumn = "Borrar la columna"
@@ -39,7 +35,6 @@ ExitExamMode2 = "examen ?"
Exponential = "Exponencial"
FillWithFormula = "Rellenar con una fórmula"
ForbiddenValue = "Valor prohibido"
-FunctionColumn = "Columna 0(0)"
FunctionOptions = "Opciones de la función"
Goto = "Ir a"
GraphTab = "Gráfico"
@@ -59,7 +54,6 @@ Navigate = "Navegar"
NEnd = "N fin"
Next = "Siguiente"
NoDataToPlot = "Ningunos datos que dibujar"
-NoFunctionToDelete = "Ninguna función que eliminar"
NoValueToCompute = "Ninguna medida que calcular"
NStart = "N inicio"
Ok = "Confirmar"
@@ -78,7 +72,6 @@ StatTab = "Medidas"
Step = "Incremento"
StorageMemoryFull1 = "La memoria está llena."
StorageMemoryFull2 = "Borre datos e intente de nuevo."
-StoreExpressionNotAllowed = "'store' no está permitido"
SyntaxError = "Error sintáctico"
Sym = "sim"
TEnd = "T fin"
@@ -91,11 +84,40 @@ ValuesTab = "Tabla"
Warning = "Cuidado"
XEnd = "X fin"
XStart = "X inicio"
-Zoom = "Zoom"
-Developers = "Desarrolladores"
-BetaTesters = "Probadores beta"
ExamModeMode = "Modo"
ExamModeModeStandard = "Estándar "
ExamModeModeNoSym = "Sin simbólico "
ExamModeModeNoSymNoText = "Sin simbólico sin texto "
ExamModeModeDutch = "Holandés "
+ColorRed = "Rojo "
+ColorBlue = "Azul "
+ColorGreen = "Verde "
+ColorYellow = "Amarillo "
+ColorPurple = "Púrpura "
+ColorCyan = "Cian "
+ColorPink = "Rosa "
+ColorOrange = "Naranja "
+TimeDimension = "Tiempo"
+DistanceDimension = "Distancia"
+MassDimension = "Masa"
+CurrentDimension = "Correr"
+TemperatureDimension = "La temperatura"
+AmountOfSubstanceDimension = "cantidad de materia"
+LuminousIntensityDimension = "Intensidad de luz"
+FrequencyDimension = "Frecuencia"
+ForceDimension = "Fuerza"
+PressureDimension = "Presión"
+EnergyDimension = "Energía"
+PowerDimension = "Potencia"
+ElectricChargeDimension = "Carga eléctrica"
+ElectricPotentialDimension = "Potencial eléctrico"
+ElectricCapacitanceDimension = "Capacidad eléctrica"
+ElectricResistanceDimension = "Resistencia eléctrica"
+ElectricConductanceDimension = "conductancia eléctrica"
+MagneticFluxDimension = "flujo magnético"
+MagneticFieldDimension = "Campo magnético"
+InductanceDimension = "Inductancia"
+CatalyticActivityDimension = "Actividad catalítica"
+SurfaceDimension = "Superficie"
+VolumeDimension = "Volumen"
+SpeedDimension = "Velocidad"
\ No newline at end of file
diff --git a/apps/shared.fr.i18n b/apps/shared.fr.i18n
index 46b76202d59..2428b309b4e 100644
--- a/apps/shared.fr.i18n
+++ b/apps/shared.fr.i18n
@@ -1,12 +1,8 @@
ActivateDeactivate = "Activer/Désactiver"
ActivateExamMode = "Activer le mode examen"
-ActivateDutchExamMode = "Activer le mode examen NL"
ActiveExamModeMessage1 = "Toutes vos données seront "
ActiveExamModeMessage2 = "supprimées si vous activez "
ActiveExamModeMessage3 = "le mode examen."
-ActiveDutchExamModeMessage1 = "Toutes vos données seront supprimées "
-ActiveDutchExamModeMessage2 = "si vous activez le mode examen."
-ActiveDutchExamModeMessage3 = "Python sera inaccessible."
Axis = "Axes"
Cancel = "Annuler"
ClearColumn = "Effacer la colonne"
@@ -39,7 +35,6 @@ ExitExamMode2 = "du mode examen ?"
Exponential = "Exponentielle"
FillWithFormula = "Remplir avec une formule"
ForbiddenValue = "Valeur interdite"
-FunctionColumn = "Colonne 0(0)"
FunctionOptions = "Options de la fonction"
Goto = "Aller à"
GraphTab = "Graphique"
@@ -59,7 +54,6 @@ Navigate = "Naviguer"
Next = "Suivant"
NEnd = "N fin"
NoDataToPlot = "Aucune donnée à tracer"
-NoFunctionToDelete = "Pas de fonction à supprimer"
NoValueToCompute = "Aucune grandeur à calculer"
NStart = "N début"
Ok = "Valider"
@@ -78,7 +72,6 @@ StatTab = "Stats"
Step = "Pas"
StorageMemoryFull1 = "La mémoire est pleine."
StorageMemoryFull2 = "Effacez des données et réessayez."
-StoreExpressionNotAllowed = "'store' n'est pas autorisé"
SyntaxError = "Attention à la syntaxe"
Sym = "sym"
TEnd = "T fin"
@@ -91,11 +84,40 @@ ValuesTab = "Tableau"
Warning = "Attention"
XEnd = "X fin"
XStart = "X début"
-Zoom = "Zoom"
-Developers = "Développeurs"
-BetaTesters = "Beta testeurs"
ExamModeMode = "Mode"
ExamModeModeStandard = "Standard "
ExamModeModeNoSym = "Sans symbolique "
ExamModeModeNoSymNoText = "Sans symbolique ni texte "
ExamModeModeDutch = "Dutch "
+ColorRed = "Rouge "
+ColorBlue = "Bleu "
+ColorGreen = "Vert "
+ColorYellow = "Jaune "
+ColorPurple = "Violet "
+ColorCyan = "Cyan "
+ColorPink = "Rose "
+ColorOrange = "Orange "
+TimeDimension = "Temps"
+DistanceDimension = "Distance"
+MassDimension = "Masse"
+CurrentDimension = "Courant"
+TemperatureDimension = "Température"
+AmountOfSubstanceDimension = "Quantité de matière"
+LuminousIntensityDimension = "Intensité lumineuse"
+FrequencyDimension = "Fréquence"
+ForceDimension = "Force"
+PressureDimension = "Pression"
+EnergyDimension = "Énergie"
+PowerDimension = "Puissance"
+ElectricChargeDimension = "Charge électrique"
+ElectricPotentialDimension = "Potentiel électrique"
+ElectricCapacitanceDimension = "Capacité électrique"
+ElectricResistanceDimension = "Résistance électrique"
+ElectricConductanceDimension = "Conductance électrique"
+MagneticFluxDimension = "Flux magnétique"
+MagneticFieldDimension = "Champ magnétique"
+InductanceDimension = "Inductance"
+CatalyticActivityDimension = "Activité catalytique"
+SurfaceDimension = "Surface"
+VolumeDimension = "Volume"
+SpeedDimension = "Vitesse"
diff --git a/apps/shared.hu.i18n b/apps/shared.hu.i18n
index 60ba0754b34..91e45f3d154 100644
--- a/apps/shared.hu.i18n
+++ b/apps/shared.hu.i18n
@@ -1,101 +1,124 @@
-ActivateDeactivate = "Ki/Be kapcsolás"
-ActivateExamMode = "A vizsgálati mód aktiválása"
-ActivateDutchExamMode = "A holland vizsga mód aktiválása"
-ActiveExamModeMessage1 = "Az összes adatod"
-ActiveExamModeMessage2 = "törölve lesz ha"
-ActiveExamModeMessage3 = "a vizsga módot aktiválja."
-ActiveDutchExamModeMessage1 = "Az összes adatod törölve lesz"
-ActiveDutchExamModeMessage2 = "ha a vizsga módot aktiválja. A"
-ActiveDutchExamModeMessage3 = "Python alkalmazás használhatatlan lesz."
-Axis = "Tengelyek"
-Cancel = "Mégse"
-ClearColumn = "Oszlop törlése"
-ColumnOptions = "Oszlop opciók"
-ConfirmDiscard1 = "Minden változtatást elvetünk"
-ConfirmDiscard2 = ""
-CopyColumnInList = "Az oszlopot egy listába másolni"
-Country = "Ország"
-CountryCA = "Kanada "
-CountryDE = "Németország "
-CountryES = "Spanyolország "
-CountryFR = "Franciaország "
-CountryGB = "Egyesült Királyság "
-CountryIT = "Olaszország "
-CountryNL = "Hollandia "
-CountryPT = "Portugália "
-CountryUS = "Egyesült Államok "
-CountryWW = "Nemzetközi "
-CountryWarning1 = "Ez a beállítás meghatározza az"
-CountryWarning2 = "alkalmazott tematikus konvenciókat."
-DataNotSuitable = "Az adatok nem felelnek meg"
-DataTab = "Adatok"
-Deg = "deg"
-Deviation = "Varianca"
-DisplayValues = "Értékek mutatása"
-Empty = "Üres"
-Eng = "eng"
-ExitExamMode1 = "Kilépni a vizsga "
-ExitExamMode2 = "módból?"
-Exponential = "Exponenciális"
-FillWithFormula = "Töltse ki egy képlettel"
-ForbiddenValue = "Tiltott érték"
-FunctionColumn = "0(0) oszlop"
-FunctionOptions = "Funkció opciók"
-Goto = "Menj ..."
-GraphTab = "Grafikon"
-HardwareTestLaunch1 = "A hardverteszt indítása :"
-HardwareTestLaunch2 = "Nyomjon a reset gombra a"
-HardwareTestLaunch3 = "teszt megállításához (ez"
-HardwareTestLaunch4 = "az adatokat törölni fogja)"
-IntervalSet = "Állítsa be az intervallumot"
-Language = "Nyelv"
-LowBattery = "Majdnem kimerült az elem"
-Mean = "középérték"
-Move = " Odébb rakni: "
-NameCannotStartWithNumber = "Egy név nem kezdöthet számmal"
-NameTaken = "Ez a név foglalt"
-NameTooLong = "Ez a név túl hosszú"
-Navigate = "Hajózik"
-Next = "következö"
-NEnd = "N vége"
-NoDataToPlot = "Nincs rajzolható adat"
-NoFunctionToDelete = "Nincs törölhetö függvény"
-NoValueToCompute = "Nincs számítható érték"
-NStart = "N kezdete"
-Ok = "Érvényesítés"
-Or = " vagy "
-Orthonormal = "Ortonormált"
-Plot = "Grafikon rajzolása"
-PoolMemoryFull1 = "A memória megtelt."
-PoolMemoryFull2 = "Kérem próbálja újra."
-Rename = "Átnevezés"
-Sci = "sci"
-SortValues = "Rendezés értékek növelésével"
-SortSizes = "Rendezés növekvő frekvenciák szerint"
-SquareSum = "Négyzetek összege"
-StandardDeviation = "Alap eltérés"
-StatTab = "Statisztikák"
-Step = "Lépés"
-StorageMemoryFull1 = "A memória megtelt."
-StorageMemoryFull2 = "Törlöljön adatokat és próbálkozzon újra."
-StoreExpressionNotAllowed = "'szore' nem engedélyezett"
-SyntaxError = "Szintaxis hiba"
-Sym = "sym"
-TEnd = "T vég"
-ThetaEnd = "θ vége"
-ThetaStart = "θ kezdete"
-TStart = "T kezdete"
-ToZoom = "Nagyítani : "
-UndefinedValue = "Meghatározatlan adat"
-ValuesTab = "Táblázat"
-Warning = "Figyelem"
-XEnd = "X vége"
-XStart = "X kezdete"
-Zoom = "Nagyítás"
-Developers = "Kifejlesztök"
-BetaTesters = "Béta tesztelök"
-ExamModeMode = "Üzemmód"
-ExamModeModeStandard = "Normál "
-ExamModeModeNoSym = "Szimbólikus nélkül "
-ExamModeModeNoSymNoText = "Szimbólikus és szöveg nélkül "
-ExamModeModeDutch = "Holland "
+ActivateDeactivate = "Ki/Be kapcsolás"
+ActivateExamMode = "A vizsgálati mód aktiválása"
+ActiveExamModeMessage1 = "Az összes adatod"
+ActiveExamModeMessage2 = "törölve lesz ha"
+ActiveExamModeMessage3 = "a vizsga módot aktiválja."
+Axis = "Tengelyek"
+Cancel = "Mégse"
+ClearColumn = "Oszlop törlése"
+ColumnOptions = "Oszlop opciók"
+ConfirmDiscard1 = "Minden változtatást elvetünk"
+ConfirmDiscard2 = ""
+CopyColumnInList = "Az oszlopot egy listába másolni"
+Country = "Ország"
+CountryCA = "Kanada "
+CountryDE = "Németország "
+CountryES = "Spanyolország "
+CountryFR = "Franciaország "
+CountryGB = "Egyesült Királyság "
+CountryIT = "Olaszország "
+CountryNL = "Hollandia "
+CountryPT = "Portugália "
+CountryUS = "Egyesült Államok "
+CountryWW = "Nemzetközi "
+CountryWarning1 = "Ez a beállítás meghatározza az"
+CountryWarning2 = "alkalmazott tematikus konvenciókat."
+DataNotSuitable = "Az adatok nem felelnek meg"
+DataTab = "Adatok"
+Deg = "deg"
+Deviation = "Varianca"
+DisplayValues = "Értékek mutatása"
+Empty = "Üres"
+Eng = "eng"
+ExitExamMode1 = "Kilépni a vizsga "
+ExitExamMode2 = "módból?"
+Exponential = "Exponenciális"
+FillWithFormula = "Töltse ki egy képlettel"
+ForbiddenValue = "Tiltott érték"
+FunctionOptions = "Funkció opciók"
+Goto = "Menj ..."
+GraphTab = "Grafikon"
+HardwareTestLaunch1 = "A hardverteszt indítása :"
+HardwareTestLaunch2 = "Nyomjon a reset gombra a"
+HardwareTestLaunch3 = "teszt megállításához (ez"
+HardwareTestLaunch4 = "az adatokat törölni fogja)"
+IntervalSet = "Állítsa be az intervallumot"
+Language = "Nyelv"
+LowBattery = "Majdnem kimerült az elem"
+Mean = "középérték"
+Move = " Odébb rakni: "
+NameCannotStartWithNumber = "Egy név nem kezdöthet számmal"
+NameTaken = "Ez a név foglalt"
+NameTooLong = "Ez a név túl hosszú"
+Navigate = "Hajózik"
+Next = "következö"
+NEnd = "N vége"
+NoDataToPlot = "Nincs rajzolható adat"
+NoValueToCompute = "Nincs számítható érték"
+NStart = "N kezdete"
+Ok = "Érvényesítés"
+Or = " vagy "
+Orthonormal = "Ortonormált"
+Plot = "Grafikon rajzolása"
+PoolMemoryFull1 = "A memória megtelt."
+PoolMemoryFull2 = "Kérem próbálja újra."
+Rename = "Átnevezés"
+Sci = "sci"
+SortValues = "Rendezés értékek növelésével"
+SortSizes = "Rendezés növekvő frekvenciák szerint"
+SquareSum = "Négyzetek összege"
+StandardDeviation = "Alap eltérés"
+StatTab = "Statisztikák"
+Step = "Lépés"
+StorageMemoryFull1 = "A memória megtelt."
+StorageMemoryFull2 = "Törlöljön adatokat és próbálkozzon újra."
+SyntaxError = "Szintaxis hiba"
+Sym = "sym"
+TEnd = "T vég"
+ThetaEnd = "θ vége"
+ThetaStart = "θ kezdete"
+TStart = "T kezdete"
+ToZoom = "Nagyítani : "
+UndefinedValue = "Meghatározatlan adat"
+ValuesTab = "Táblázat"
+Warning = "Figyelem"
+XEnd = "X vége"
+XStart = "X kezdete"
+ExamModeMode = "Üzemmód"
+ExamModeModeStandard = "Normál "
+ExamModeModeNoSym = "Szimbólikus nélkül "
+ExamModeModeNoSymNoText = "Szimbólikus és szöveg nélkül "
+ExamModeModeDutch = "Holland "
+ColorRed = "Piros "
+ColorBlue = "Kék "
+ColorGreen = "Zöld "
+ColorYellow = "Sárga "
+ColorPurple = "Lila "
+ColorCyan = "Cián "
+ColorPink = "Rózsaszín "
+ColorOrange = "Narancssárga "
+TimeDimension = "Idő"
+DistanceDimension = "Távolság"
+MassDimension = "Tömeg"
+CurrentDimension = "Futó"
+TemperatureDimension = "Hőfok"
+AmountOfSubstanceDimension = "Az anyag mennyisége"
+LuminousIntensityDimension = "Fény intenzitása"
+FrequencyDimension = "Frekvencia"
+ForceDimension = "Erő"
+PressureDimension = "Nyomás"
+EnergyDimension = "Energia"
+PowerDimension = "Erős"
+ElectricChargeDimension = "Elektromos töltő"
+ElectricPotentialDimension = "Elektromos potenciál"
+ElectricCapacitanceDimension = "Elektromos kapacitás"
+ElectricResistanceDimension = "Elektromos ellenállás"
+ElectricConductanceDimension = "elektromos vezetőképesség"
+MagneticFluxDimension = "mágneses fluxus"
+MagneticFieldDimension = "Mágneses mező"
+InductanceDimension = "Induktivitás"
+CatalyticActivityDimension = "Katalitikus aktivitás"
+SurfaceDimension = "Felület"
+VolumeDimension = "Hangerő"
+SpeedDimension = "Sebesség"
+Factorial = "Faktorál"
diff --git a/apps/shared.it.i18n b/apps/shared.it.i18n
index 3322800c8c5..d1932fbd34b 100644
--- a/apps/shared.it.i18n
+++ b/apps/shared.it.i18n
@@ -1,12 +1,8 @@
ActivateDeactivate = "Attivare/Disattivare"
ActivateExamMode = "Attiva modalità d'esame"
-ActivateDutchExamMode = "Attiva modalità d'esame NL"
ActiveExamModeMessage1 = "Tutti i tuoi dati saranno "
ActiveExamModeMessage2 = "cancellati se attivi "
ActiveExamModeMessage3 = "la modalità d'esame."
-ActiveDutchExamModeMessage1 = "Tutti i tuoi dati saranno cancellati"
-ActiveDutchExamModeMessage2 = "se attivi la modalità d'esame."
-ActiveDutchExamModeMessage3 = "L'app Python sarà inaccessibile."
Axis = "Assi"
Cancel = "Annullare"
ClearColumn = "Cancella la colonna"
@@ -39,7 +35,6 @@ ExitExamMode2 = "dalla modalità d'esame ?"
Exponential = "Esponenziale"
FillWithFormula = "Compilare con una formula"
ForbiddenValue = "Valore non consentito"
-FunctionColumn = "Colonna 0(0)"
FunctionOptions = "Opzioni della funzione"
Goto = "Andare a"
GraphTab = "Grafico"
@@ -59,7 +54,6 @@ Navigate = "Navigare"
Next = "Successivo"
NEnd = "N finale"
NoDataToPlot = "Nessun dato da tracciare"
-NoFunctionToDelete = "Nessuna funzione da cancellare"
NoValueToCompute = "Nessun valore da calcolare"
NStart = "N iniziale"
Ok = "Conferma"
@@ -78,7 +72,6 @@ StatTab = "Stats"
Step = "Passo"
StorageMemoryFull1 = "La memoria è piena."
StorageMemoryFull2 = "Cancellate i dati e riprovate."
-StoreExpressionNotAllowed = "'store' non è consentito"
SyntaxError = "Sintassi errata"
Sym = "sym"
TEnd = "T finale"
@@ -91,11 +84,41 @@ ValuesTab = "Tabella"
Warning = "Attenzione"
XEnd = "X finale"
XStart = "X iniziale"
-Zoom = "Zoom"
-Developers = "Developers"
-BetaTesters = "Beta testers"
ExamModeMode = "Modalità"
ExamModeModeStandard = "Standard "
ExamModeModeNoSym = "Nessun simbolo "
ExamModeModeNoSymNoText = "Nessun simbolo nessun testo "
ExamModeModeDutch = "Olandese "
+ColorRed = "Rosso "
+ColorBlue = "Blu "
+ColorGreen = "Verde "
+ColorYellow = "Giallo "
+ColorPurple = "Viola "
+ColorCyan = "Ciano"
+ColorPink = "Rosa "
+ColorOrange = "Arancia "
+TimeDimension = "Volta"
+DistanceDimension = "Distanza"
+MassDimension = "Messa"
+CurrentDimension = "In esecuzione"
+TemperatureDimension = "Temperatura"
+AmountOfSubstanceDimension = "Quantità di materia"
+LuminousIntensityDimension = "Intensità luminosa"
+FrequencyDimension = "Frequenza"
+ForceDimension = "Forza"
+PressureDimension = "Pressione"
+EnergyDimension = "Energia"
+PowerDimension = "Potere"
+ElectricChargeDimension = "Carica elettrica"
+ElectricPotentialDimension = "Potenziale elettrico"
+ElectricCapacitanceDimension = "Capacità elettrica"
+ElectricResistanceDimension = "Resistenza elettrica"
+ElectricConductanceDimension = "conduttanza elettrica"
+MagneticFluxDimension = "flusso magnetico"
+MagneticFieldDimension = "Campo magnetico"
+InductanceDimension = "Induttanza"
+CatalyticActivityDimension = "Attività catalitica"
+SurfaceDimension = "Superficie"
+VolumeDimension = "Volume"
+SpeedDimension = "Velocità"
+Factorial = "Fattoriale"
diff --git a/apps/shared.nl.i18n b/apps/shared.nl.i18n
index b3971aa6cfe..e63e98605c5 100644
--- a/apps/shared.nl.i18n
+++ b/apps/shared.nl.i18n
@@ -1,12 +1,8 @@
ActivateDeactivate = "Zet aan/uit"
ActivateExamMode = "Internationale examenst."
-ActivateDutchExamMode = "Nederlandse examenstand"
ActiveExamModeMessage1 = "Al je gegevens worden "
ActiveExamModeMessage2 = "gewist wanneer je de "
ActiveExamModeMessage3 = "examenstand activeert."
-ActiveDutchExamModeMessage1 = "Al je gegevens worden gewist wanneer"
-ActiveDutchExamModeMessage2 = "je de examenstand activeert. De Python"
-ActiveDutchExamModeMessage3 = "applicatie wordt uitgeschakeld."
Axis = "Assen"
Cancel = "Annuleer"
ClearColumn = "Wis kolom"
@@ -39,7 +35,6 @@ ExitExamMode2 = "examenstand?"
Exponential = "Exponentieel"
FillWithFormula = "Vul met een formule"
ForbiddenValue = "Verboden waarde"
-FunctionColumn = "0(0) kolom"
FunctionOptions = "Functie-opties"
Goto = "Ga naar"
GraphTab = "Grafiek"
@@ -58,7 +53,6 @@ NameTooLong = "Deze naam is te lang"
Navigate = "Navigeren"
Next = "Volgende"
NoDataToPlot = "Geen gegevens om te plotten"
-NoFunctionToDelete = "Geen functie om te verwijderen"
NoValueToCompute = "Geen waarden om te berekenen"
NEnd = "N einde"
NStart = "N begin"
@@ -74,7 +68,6 @@ SortValues = "Sorteer waarden oplopend"
SortSizes = "Sorteer frequenties oplopend"
SquareSum = "Som van kwadraten"
StandardDeviation = "Standaardafwijking"
-StoreExpressionNotAllowed = "'opslaan' is niet toegestaan"
StatTab = "Stats"
Step = "Stap"
StorageMemoryFull1 = "Het geheugen is vol."
@@ -91,11 +84,41 @@ ValuesTab = "Tabel"
Warning = "Waarschuwing"
XEnd = "X einde"
XStart = "X begin"
-Zoom = "Zoom"
-Developers = "Developers"
-BetaTesters = "Beta testers"
ExamModeMode = "Mode"
ExamModeModeStandard = "Standaard "
ExamModeModeNoSym = "Geen sym "
ExamModeModeNoSymNoText = "Geen sym geen tekst "
ExamModeModeDutch = "Nederlands "
+ColorRed = "rood"
+ColorBlue = "Blauw"
+ColorGreen = "Groente"
+ColorYellow = "Geel"
+ColorPurple = "Purper"
+ColorCyan = "Cyaan "
+ColorPink = "Roze"
+ColorOrange = "Oranje"
+TimeDimension = "Tijd"
+DistanceDimension = "Afstand"
+MassDimension = "Massa"
+CurrentDimension = "Rennen"
+TemperatureDimension = "Temperatuur"
+AmountOfSubstanceDimension = "Hoeveelheid materie"
+LuminousIntensityDimension = "Lichtsterkte"
+FrequencyDimension = "Frequentie"
+ForceDimension = "Kracht"
+PressureDimension = "Druk"
+EnergyDimension = "Energie"
+PowerDimension = "Kracht"
+ElectricChargeDimension = "Elektrische lading"
+ElectricPotentialDimension = "elektrische potentiaal"
+ElectricCapacitanceDimension = "elektrische capaciteit:"
+ElectricResistanceDimension = "Elektrische weerstand"
+ElectricConductanceDimension = "elektrische geleiding:"
+MagneticFluxDimension = "magnetische flux"
+MagneticFieldDimension = "Magnetisch veld"
+InductanceDimension = "Inductie"
+CatalyticActivityDimension = "Katalytische activiteit"
+SurfaceDimension = "Oppervlak"
+VolumeDimension = "Volume"
+SpeedDimension = "Snelheid"
+Factorial = "Faculteit"
diff --git a/apps/shared.pt.i18n b/apps/shared.pt.i18n
index 39fa24c1261..de0852119a3 100644
--- a/apps/shared.pt.i18n
+++ b/apps/shared.pt.i18n
@@ -1,12 +1,8 @@
ActivateDeactivate = "Ativar/Desativar"
ActivateExamMode = "Ativar o modo de exame"
-ActivateDutchExamMode = "Ativar o modo de exame NL"
ActiveExamModeMessage1 = "Todos os seus dados serão "
ActiveExamModeMessage2 = "apagados se ativar "
ActiveExamModeMessage3 = "o modo de exame."
-ActiveDutchExamModeMessage1 = "Todos os seus dados serão apagados "
-ActiveDutchExamModeMessage2 = "se ativar o modo de exame. A"
-ActiveDutchExamModeMessage3 = "aplicação Python estará indisponível."
Axis = "Eixos"
Cancel = "Cancelar"
ClearColumn = "Excluir coluna"
@@ -39,7 +35,6 @@ ExitExamMode2 = "exame ?"
Exponential = "Exponencial"
FillWithFormula = "Preencher com uma fórmula"
ForbiddenValue = "Valor proibido"
-FunctionColumn = "Coluna 0(0)"
FunctionOptions = "Opções de função"
Goto = "Ir para"
GraphTab = "Gráfico"
@@ -59,7 +54,6 @@ Navigate = "Navegar"
NEnd = "N fim"
Next = "Seguinte"
NoDataToPlot = "Não há dados para desenhar"
-NoFunctionToDelete = "Sem função para eliminar"
NoValueToCompute = "Não há dados para calcular"
NStart = "N início"
Ok = "Confirmar"
@@ -78,7 +72,6 @@ StatTab = "Estat"
Step = "Passo"
StorageMemoryFull1 = "A memória esta cheia."
StorageMemoryFull2 = "Apage dados e tente novamente."
-StoreExpressionNotAllowed = "'store' não está permitido"
SyntaxError = "Erro de sintaxe"
Sym = "sim"
TEnd = "T fim"
@@ -91,11 +84,40 @@ ValuesTab = "Tabela"
Warning = "Atenção"
XEnd = "X fim"
XStart = "X início"
-Zoom = "Zoom"
-Developers = "Desenvolvedores"
-BetaTesters = "Testadores beta"
ExamModeMode = "Modo"
ExamModeModeStandard = "Padrão "
ExamModeModeNoSym = "Sem sym "
ExamModeModeNoSymNoText = "Sem sym sem texto "
ExamModeModeDutch = "holandês "
+ColorRed = "Vermelho "
+ColorBlue = "Azul "
+ColorGreen = "Verde "
+ColorYellow = "Amarelo "
+ColorPurple = "Roxa "
+ColorCyan = "Ciano"
+ColorPink = "Cor de rosa "
+ColorOrange = "Laranja "
+TimeDimension = "Tempo"
+DistanceDimension = "Distância"
+MassDimension = "Massa"
+CurrentDimension = "Corrida"
+TemperatureDimension = "Temperatura"
+AmountOfSubstanceDimension = "Quantidade de matéria"
+LuminousIntensityDimension = "Intensidade da luz"
+FrequencyDimension = "Frequência"
+ForceDimension = "Força"
+PressureDimension = "Pressão"
+EnergyDimension = "Energia"
+PowerDimension = "Poderoso"
+ElectricChargeDimension = "Carga elétrica"
+ElectricPotentialDimension = "Potencial elétrico"
+ElectricCapacitanceDimension = "Capacidade elétrica"
+ElectricResistanceDimension = "Resistência elétrica"
+ElectricConductanceDimension = "condutância elétrica"
+MagneticFluxDimension = "fluxo magnético"
+MagneticFieldDimension = "Campo magnético"
+InductanceDimension = "Indutância"
+CatalyticActivityDimension = "Atividade catalítica"
+SurfaceDimension = "Superfície"
+VolumeDimension = "Volume"
+SpeedDimension = "Velocidade"
diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n
index fb927a65962..f38ad608540 100644
--- a/apps/shared.universal.i18n
+++ b/apps/shared.universal.i18n
@@ -25,7 +25,6 @@ UnitMassGramKiloSymbol = "_kg"
UnitMassGramSymbol = "_g"
UnitMassGramMilliSymbol = "_mg"
UnitMassGramMicroSymbol = "_μg"
-UnitMassGramNanoSymbol = "_ng"
UnitMassTonneSymbol = "_t"
UnitMassOunceSymbol = "_oz"
UnitMassPoundSymbol = "_lb"
@@ -122,11 +121,12 @@ DeterminantCommandWithArg = "det(M)"
DiffCommandWithArg = "diff(f(x),x,a)"
DiffCommand = "diff(\x11,x,\x11)"
DimensionCommandWithArg = "dim(M)"
-DiscriminantFormulaDegree2 = "Δ=b^2-4ac"
DotCommandWithArg = "dot(u,v)"
E = "e"
Equal = "="
FactorCommandWithArg = "factor(n)"
+FactorialCommand = "!"
+FactorialCommandWithArg = "n!"
FccId = "FCC ID"
FloorCommandWithArg = "floor(x)"
FracCommandWithArg = "frac(x)"
@@ -315,6 +315,16 @@ ElementTsMass = "294"
ElementOgMass = "294"
ElementUueMass = "295"
ElementUbnMass = "297"
+LaurianFournier = "Laurian Fournier"
+PLaurianFournier = "@Lauryy06"
+YannCouturier = "Yann Couturier"
+PYannCouturier = "@Yaya-Cout"
+LoicE = "Loïc E."
+PLoicE = "@lolocomotive"
+DavidLuca = "David Luca"
+PDavidLuca = "@dl11"
+VictorKretz = "Victor Kretz"
+PVictorKretz = "@Mino"
QuentinGuidee = "Quentin Guidée"
PQuentinGuidee = "@quentinguidee"
SandraSimmons = "Sandra Simmons"
@@ -341,24 +351,7 @@ VenceslasDuet = "Venceslas Duet"
PVenceslasDuet = "@Citorva"
CyprienMejat = "Cyprien Méjat"
PCyprienMejat = "@A2drien"
-TimeoArnouts = "Timéo Arnouts"
-PTimeoArnouts = "@Dogm"
-JulieC = "Julie C."
-PJulieC = "@windows9x95"
-LelahelHideux = "Lélahel Hideux"
-PLelahelHideux = "@Lelahelry"
-Madil = "Madil"
-PMadil = "@le-grand-mannitout"
-HilaireLeRoux = "Hilaire Le Roux"
-PHilaireLeRoux = "@0Babass2"
-HectorNussbaumer = "Hector Nussbaumer"
-PHectorNussbaumer = "@Sycorax"
-RaphaelDyda = "Raphaël Dyda"
-PRaphaelDyda = "@Trixciel"
-ThibautC = "Thibaut C."
-PThibautC = "@Tibo_C"
SpeedOfLight = "2.99792458·10^8_m_s^-1"
-YearLight = "9.461·10^15_m"
Boltzmann = "1.380649·10^-23_J_K^-1"
StefanBoltzmann = "5.670374419·10^-8_W_m^-2_K^-4"
VacuumImpedance = "376.730313668_Ω"
@@ -458,3 +451,39 @@ HartreeConstant = "4.3597447222071·10^-18_J"
MagneticFluxQuantum = "2.067833848·10^-15_Wb"
ConductanceQuantum = "7.748091729·10^-5_S"
CirculationQuantum = "3.6369475516·10^-4_m^2_s^-1"
+Cndcvt_Silver = "6.30·10^7_S_m^-1"
+Cndcvt_Copper = "5.96·10^7_S_m^-1"
+Cndcvt_Gold = "4.11·10^7_S_m^-1"
+Cndcvt_Aluminium = "3.77·10^7_S_m^-1"
+Cndcvt_Calcium = "2.98·10^7_S_m^-1"
+Cndcvt_Tungsten = "1.79·10^7_S_m^-1"
+Cndcvt_Zinc = "1.69·10^7_S_m^-1"
+Cndcvt_Cobalt = "1.60·10^7_S_m^-1"
+Cndcvt_Nickel = "1.43·10^7_S_m^-1"
+Cndcvt_Lithium = "1.08·10^7_S_m^-1"
+Cndcvt_Iron = "1.00·10^7_S_m^-1"
+Cndcvt_Platinum = "9.43·10^6_S_m^-1"
+Cndcvt_Tin = "9.17·10^6_S_m^-1"
+Cndcvt_Sea_water = "4.80_S_m^-1"
+Cndcvt_Water = "5.00·10^-3_S_m^-1"
+Cndcvt_Air = "1.00·10^-13_S_m^-1"
+Cndcvt_Glass = "1.00·10^-13_S_m^-1"
+Cndcvt_Wood = "1.00·10^-3_S_m^-1"
+Rstvt_Silver = "1.59·10^-8_Ω_m"
+Rstvt_Copper = "1.68·10^-8_Ω_m"
+Rstvt_Gold = "2.44·10^-8_Ω_m"
+Rstvt_Aluminium = "2.65·10^-8_Ω_m"
+Rstvt_Calcium = "3.36·10^-8_Ω_m"
+Rstvt_Tungsten = "5.60·10^-8_Ω_m"
+Rstvt_Zinc = "5.90·10^-8_Ω_m"
+Rstvt_Cobalt = "6.24·10^-8_Ω_m"
+Rstvt_Nickel = "6.99·10^-8_Ω_m"
+Rstvt_Lithium = "9.28·10^-8_Ω_m"
+Rstvt_Iron = "9.70·10^-8_Ω_m"
+Rstvt_Platinum = "1.06·10^-7_Ω_m"
+Rstvt_Tin = "1.09·10^-7_Ω_m"
+Rstvt_Sea_water = "2.1·10^-1_Ω_m"
+Rstvt_Water = "1.01·10^3_Ω_m"
+Rstvt_Air = "1.00·10^9_Ω_m"
+Rstvt_Glass = "5.00·10^14_Ω_m"
+Rstvt_Wood = "1.00·10^3_Ω_m"
diff --git a/apps/shared/Makefile b/apps/shared/Makefile
index bd421f508a6..1d0530e7383 100644
--- a/apps/shared/Makefile
+++ b/apps/shared/Makefile
@@ -29,6 +29,8 @@ app_shared_src = $(addprefix apps/shared/,\
buffer_function_title_cell.cpp \
buffer_text_view_with_text_field.cpp \
button_with_separator.cpp \
+ color_cell.cpp \
+ color_parameter_controller.cpp \
cursor_view.cpp \
editable_cell_table_view_controller.cpp \
expression_field_delegate_app.cpp \
diff --git a/apps/shared/banner_view.h b/apps/shared/banner_view.h
index b1ad6e5fc5d..23424dec4e9 100644
--- a/apps/shared/banner_view.h
+++ b/apps/shared/banner_view.h
@@ -12,7 +12,7 @@ class BannerView : public View {
KDSize minimalSizeForOptimalDisplay() const override;
KDCoordinate minimalHeightForOptimalDisplayGivenWidth(KDCoordinate width) const;
void reload() { layoutSubviews(); }
- static constexpr const KDFont * Font() { return KDFont::SmallFont; }
+ static constexpr const KDFont * Font() { return KDFont::ItalicSmallFont; }
static constexpr KDColor TextColor() { return Palette::PrimaryText; }
static constexpr KDColor BackgroundColor() { return Palette::SubMenuBackground; }
private:
diff --git a/apps/shared/color_cell.cpp b/apps/shared/color_cell.cpp
new file mode 100644
index 00000000000..a43e3f3ea5b
--- /dev/null
+++ b/apps/shared/color_cell.cpp
@@ -0,0 +1,51 @@
+#include "color_cell.h"
+
+namespace Shared {
+
+constexpr const I18n::Message MessageTableCellWithColor::k_textForIndex[Palette::numberOfDataColors()];
+
+constexpr const uint8_t colorMask[MessageTableCellWithColor::ColorView::k_colorSize][MessageTableCellWithColor::ColorView::k_colorSize] = { // FIXME Can't link with constexpr static
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0xFF, 0xE1, 0x0C, 0x00, 0x00, 0x0C, 0xE1, 0xFF, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xFF, 0xFF},
+ {0xFF, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xFF},
+ {0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xFF},
+ {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF},
+ {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF},
+ {0xFF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xFF},
+ {0xFF, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xFF},
+ {0xFF, 0xFF, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0xFF, 0xE1, 0x0C, 0x00, 0x00, 0x0C, 0xE1, 0xFF, 0xFF, 0xFF},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+};
+
+MessageTableCellWithColor::MessageTableCellWithColor() :
+ MessageTableCell(),
+ m_accessoryView()
+ {}
+
+View * MessageTableCellWithColor::accessoryView() const {
+ return (View *)&m_accessoryView;
+}
+
+void MessageTableCellWithColor::setColor(int i) {
+ m_accessoryView.setColor(i);
+ MessageTextView * label = (MessageTextView*)(labelView());
+ return label->setMessage(k_textForIndex[i]);
+}
+
+MessageTableCellWithColor::ColorView::ColorView() :
+ m_index(0)
+ {}
+
+void MessageTableCellWithColor::ColorView::drawRect(KDContext * ctx, KDRect rect) const {
+ KDColor Buffer[MessageTableCellWithColor::ColorView::k_colorSize*MessageTableCellWithColor::ColorView::k_colorSize];
+ KDRect Frame(bounds().x(), bounds().y() + bounds().height()/2 - k_colorSize/2, k_colorSize, k_colorSize);
+ ctx->blendRectWithMask(Frame, Palette::DataColor[m_index], (const uint8_t *)colorMask, Buffer);
+}
+
+KDSize MessageTableCellWithColor::ColorView::minimalSizeForOptimalDisplay() const {
+ return KDSize(k_colorSize, k_colorSize);
+}
+
+}
diff --git a/apps/shared/color_cell.h b/apps/shared/color_cell.h
new file mode 100644
index 00000000000..1951cd68015
--- /dev/null
+++ b/apps/shared/color_cell.h
@@ -0,0 +1,42 @@
+#ifndef SHARED_COLOR_CELL_CONTROLLER_H
+#define SHARED_COLOR_CELL_CONTROLLER_H
+
+#include
+#include
+
+namespace Shared {
+
+class MessageTableCellWithColor : public MessageTableCell<> {
+public:
+ MessageTableCellWithColor();
+ View * accessoryView() const override;
+ void setColor(int i);
+ int color() { return m_accessoryView.color(); }
+ constexpr static I18n::Message k_textForIndex[Palette::numberOfDataColors()] = {
+ I18n::Message::ColorRed,
+ I18n::Message::ColorBlue,
+ I18n::Message::ColorGreen,
+ I18n::Message::ColorYellow,
+ I18n::Message::ColorPurple,
+ I18n::Message::ColorCyan,
+ I18n::Message::ColorPink,
+ I18n::Message::ColorOrange
+ };
+ class ColorView : public TransparentView {
+ public:
+ ColorView();
+ void setColor(int i) { m_index = i; }
+ int color() { return m_index; }
+ void drawRect(KDContext * ctx, KDRect rect) const override;
+ KDSize minimalSizeForOptimalDisplay() const override;
+ constexpr static KDCoordinate k_colorSize = 12;
+ private:
+ int m_index;
+ };
+private:
+ ColorView m_accessoryView;
+};
+
+}
+
+#endif
diff --git a/apps/shared/color_parameter_controller.cpp b/apps/shared/color_parameter_controller.cpp
new file mode 100644
index 00000000000..2b2e4ef8d81
--- /dev/null
+++ b/apps/shared/color_parameter_controller.cpp
@@ -0,0 +1,86 @@
+#include "color_parameter_controller.h"
+
+#include "function_app.h"
+#include "../apps_container.h"
+#include
+
+namespace Shared {
+
+ColorParameterController::ColorParameterController(Responder * parentResponder, I18n::Message title) :
+ ViewController(parentResponder),
+ m_selectableTableView(this),
+ m_record(),
+ m_title(title)
+{}
+
+void ColorParameterController::viewWillAppear() {
+ ViewController::viewWillAppear();
+ // Restore the selected color
+ KDColor FunctionColor = function()->color();
+ uint8_t cellXPosition = 0;
+ // TODO: Improve this if possible
+ for (uint8_t i = 0; i < sizeof(Palette::DataColor)/sizeof(Palette::DataColor[0]); i++) {
+ if (Palette::DataColor[i] == FunctionColor) {
+ cellXPosition = i;
+ break;
+ }
+ }
+ assert(Palette::DataColor[cellXPosition] == FunctionColor);
+ selectCellAtLocation(0, cellXPosition);
+ m_selectableTableView.reloadData();
+}
+
+void ColorParameterController::didBecomeFirstResponder() {
+ Container::activeApp()->setFirstResponder(&m_selectableTableView);
+}
+
+bool ColorParameterController::handleEvent(Ion::Events::Event event) {
+ StackViewController * stack = (StackViewController *)(parentResponder());
+ if (event == Ion::Events::Left) {
+ stack->pop();
+ return true;
+ }
+ if (event == Ion::Events::OK || event == Ion::Events::EXE) {
+ handleEnterOnRow(selectedRow());
+ stack->pop();
+ return true;
+ }
+ return false;
+}
+
+KDCoordinate ColorParameterController::cellHeight() {
+ return Metric::ParameterCellHeight;
+}
+
+HighlightCell * ColorParameterController::reusableCell(int index) {
+ assert(index < numberOfRows());
+ return &m_cells[index];
+}
+
+void ColorParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) {
+ MessageTableCellWithColor * myCell = (MessageTableCellWithColor *)cell;
+ myCell->setColor(index);
+ myCell->setMessageFont(KDFont::LargeFont);
+ cell->reloadCell();
+}
+
+bool ColorParameterController::handleEnterOnRow(int rowIndex) {
+ function()->setColor(Palette::DataColor[rowIndex]);
+ return true;
+}
+
+void ColorParameterController::setRecord(Ion::Storage::Record record) {
+ m_record = record;
+ selectCellAtLocation(0, 0);
+}
+
+ExpiringPointer ColorParameterController::function() {
+ return functionStore()->modelForRecord(m_record);
+}
+
+FunctionStore * ColorParameterController::functionStore() {
+ return FunctionApp::app()->functionStore();
+}
+
+
+}
diff --git a/apps/shared/color_parameter_controller.h b/apps/shared/color_parameter_controller.h
new file mode 100644
index 00000000000..416e9401924
--- /dev/null
+++ b/apps/shared/color_parameter_controller.h
@@ -0,0 +1,44 @@
+#ifndef SHARED_COLOR_PARAM_CONTROLLER_H
+#define SHARED_COLOR_PARAM_CONTROLLER_H
+
+#include
+#include "function_store.h"
+#include "color_cell.h"
+#include
+
+namespace Shared {
+
+class ColorParameterController : public ViewController, public SimpleListViewDataSource, public SelectableTableViewDataSource {
+public:
+ ColorParameterController(Responder * parentResponder, I18n::Message title);
+
+ View * view() override { return &m_selectableTableView; }
+ void viewWillAppear() override;
+ void didBecomeFirstResponder() override;
+
+ const char * title() override { return I18n::translate(m_title); }
+
+ bool handleEvent(Ion::Events::Event event) override;
+
+ TELEMETRY_ID("ColorParameter");
+
+ void setRecord(Ion::Storage::Record record);
+
+ int numberOfRows() const override { return Palette::numberOfDataColors(); }
+ KDCoordinate cellHeight() override;
+ HighlightCell * reusableCell(int index) override;
+ int reusableCellCount() const override { return Palette::numberOfDataColors(); } // FIXME Display issue
+ void willDisplayCellForIndex(HighlightCell * cell, int index);
+private:
+ bool handleEnterOnRow(int rowIndex);
+ FunctionStore * functionStore();
+ ExpiringPointer function();
+ SelectableTableView m_selectableTableView;
+ Ion::Storage::Record m_record;
+ I18n::Message m_title;
+ MessageTableCellWithColor m_cells[Palette::numberOfDataColors()];
+};
+
+}
+
+#endif
diff --git a/apps/shared/continuous_function.cpp b/apps/shared/continuous_function.cpp
index e127feed520..39c705ecd08 100644
--- a/apps/shared/continuous_function.cpp
+++ b/apps/shared/continuous_function.cpp
@@ -270,7 +270,7 @@ void ContinuousFunction::rangeForDisplay(float * xMin, float * xMax, float * yMi
}
if (!basedOnCostlyAlgorithms(context)) {
- Zoom::ValueAtAbscissa evaluation = [](float x, Context * context, const void * auxiliary) {
+ Zoom::ValueAtAbscissa evaluation = [](float x, Context * context, const void * auxiliary) -> float {
/* When evaluating sin(x)/x close to zero using the standard sine function,
* one can detect small variations, while the cardinal sine is supposed to be
* locally monotonous. To smooth our such variations, we round the result of
diff --git a/apps/shared/continuous_function_cache.cpp b/apps/shared/continuous_function_cache.cpp
index 00a8cd687d3..5ff498052b8 100644
--- a/apps/shared/continuous_function_cache.cpp
+++ b/apps/shared/continuous_function_cache.cpp
@@ -65,7 +65,11 @@ void ContinuousFunctionCache::ComputeNonCartesianSteps(float * tStep, float * tC
const int numberOfWholeSteps = static_cast(Graph::GraphView::k_graphStepDenominator);
static_assert(numberOfCacheablePoints % numberOfWholeSteps == 0, "numberOfCacheablePoints should be a multiple of numberOfWholeSteps for optimal caching");
const int multiple = numberOfCacheablePoints / numberOfWholeSteps;
+ // Ignore this on Casio calculators for now, as the screen resolution breaks this
+ // TODO: fix this. if it's possible
+ #ifndef _FXCG
static_assert(multiple && !(multiple & (multiple - 1)), "multiple should be a power of 2 for optimal caching");
+ #endif
/* Define cacheStep such that every whole graph steps are equally divided
* For instance, with :
* graphStepDenominator = 10.1
diff --git a/apps/shared/double_pair_store.cpp b/apps/shared/double_pair_store.cpp
index b35c56de70f..f78d4f08133 100644
--- a/apps/shared/double_pair_store.cpp
+++ b/apps/shared/double_pair_store.cpp
@@ -115,15 +115,15 @@ bool DoublePairStore::seriesNumberOfAbscissaeGreaterOrEqualTo(int series, int i)
if (count >= i) {
return true;
}
- double currentAbsissa = m_data[series][0][j];
- bool firstOccurence = true;
+ double currentAbscissa = m_data[series][0][j];
+ bool firstOccurrence = true;
for (int k = 0; k < j; k++) {
- if (m_data[series][0][k] == currentAbsissa) {
- firstOccurence = false;
+ if (m_data[series][0][k] == currentAbscissa) {
+ firstOccurrence = false;
break;
}
}
- if (firstOccurence) {
+ if (firstOccurrence) {
count++;
}
}
diff --git a/apps/shared/expression_field_delegate_app.h b/apps/shared/expression_field_delegate_app.h
index 0e175281355..466e5eb2153 100644
--- a/apps/shared/expression_field_delegate_app.h
+++ b/apps/shared/expression_field_delegate_app.h
@@ -9,6 +9,7 @@ namespace Shared {
class ExpressionFieldDelegateApp : public TextFieldDelegateApp, public LayoutFieldDelegate {
public:
virtual ~ExpressionFieldDelegateApp() = default;
+ void layoutFieldDidReceiveNoneXNTEvent() override { AppsContainer::sharedAppsContainer()->resetXNT(); }
bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) override;
bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) override;
protected:
diff --git a/apps/shared/expression_model.cpp b/apps/shared/expression_model.cpp
index 54170b6447a..d37e6b4cada 100644
--- a/apps/shared/expression_model.cpp
+++ b/apps/shared/expression_model.cpp
@@ -72,7 +72,7 @@ Expression ExpressionModel::expressionReduced(const Storage::Record * record, Po
if (isCircularlyDefined(record, context)) {
m_expression = Undefined::Builder();
} else {
- m_expression = Expression::ExpressionFromAddress(expressionAddress(record), expressionSize(record));
+ m_expression = Expression::ExpressionFromAddress(expressionAddress(record), expressionSize(record), record);
/* 'Simplify' routine might need to call expressionReduced on the very
* same function. So we need to keep a valid m_expression while executing
* 'Simplify'. Thus, we use a temporary expression. */
@@ -90,7 +90,7 @@ Expression ExpressionModel::expressionReduced(const Storage::Record * record, Po
Expression ExpressionModel::expressionClone(const Storage::Record * record) const {
assert(record->fullName() != nullptr);
/* A new Expression has to be created at each call (because it might be tempered with after calling) */
- return Expression::ExpressionFromAddress(expressionAddress(record), expressionSize(record));
+ return Expression::ExpressionFromAddress(expressionAddress(record), expressionSize(record), record);
/* TODO
* The substitution of UCodePointUnknown back and forth is done in the
* methods text, setContent (through BuildExpressionFromText), layout and
@@ -125,6 +125,39 @@ Ion::Storage::Record::ErrorStatus ExpressionModel::setExpressionContent(Ion::Sto
Ion::Storage::Record::Data newData = record->value();
size_t previousExpressionSize = expressionSize(record);
size_t newExpressionSize = newExpression.isUninitialized() ? 0 : newExpression.size();
+#ifdef STRING_STORAGE
+ size_t stringsize = 0;
+ char buf[1024] = {0};
+ char repl = 0;
+ buf[0] = '"';
+ if (!newExpression.isUninitialized()) {
+ size_t l = newExpression.serialize(buf+1,sizeof(buf)-2);
+ if (l >= sizeof(buf) - 3) {
+ newExpressionSize = 0;
+ } else {
+ buf[l + 1] = '"';
+ // replace 0x1 by x for func or n for seq
+ const char * name = record->fullName();
+ int namel = strlen(name);
+ if (namel > 4 && strncmp(name + namel - 4, ".seq", 4) == 0) {
+ repl = 'n';
+ } else if (namel > 5 && strncmp(name + namel - 5, ".func", 5) == 0) {
+ repl = 'x';
+ }
+ if (repl) {
+ for (char * ptr = buf; *ptr; ++ptr) {
+ if (*ptr == 1) {
+ *ptr = repl;
+ }
+ }
+ }
+ stringsize= l + 3; // 2 quotes and 0 at end
+ if (newExpressionSize < stringsize) {
+ newExpressionSize = stringsize;
+ }
+ }
+ }
+#endif
size_t previousDataSize = newData.size;
size_t newDataSize = previousDataSize - previousExpressionSize + newExpressionSize;
void * expAddress = expressionAddress(record);
@@ -140,10 +173,16 @@ Ion::Storage::Record::ErrorStatus ExpressionModel::setExpressionContent(Ion::Sto
* (as it is sometimes computed from metadata). Thus, the expression address
* is given as a parameter to updateNewDataWithExpression. */
updateNewDataWithExpression(record, newExpression, expAddress, newExpressionSize, previousExpressionSize);
+#ifdef STRING_STORAGE
+ if (stringsize && stringsizesetValue(newData);
- // Any error would have occured at the first call to setValue
+ // Any error would have occurred at the first call to setValue
assert(error == Ion::Storage::Record::ErrorStatus::None);
/* Here we delete only the elements relative to the expression model kept in
diff --git a/apps/shared/expression_model_handle.h b/apps/shared/expression_model_handle.h
index 8d6229a1825..812f218a6e8 100644
--- a/apps/shared/expression_model_handle.h
+++ b/apps/shared/expression_model_handle.h
@@ -23,7 +23,6 @@ class ExpressionModelHandle : public Ion::Storage::Record {
* not defined. We thus have to keep both methods. */
virtual bool isDefined();
virtual bool isEmpty();
- virtual bool shouldBeClearedBeforeRemove() { return !isEmpty(); }
/* tidy is responsible to tidy the whole model whereas tidyExpressionModel
* tidies only the members associated with the ExpressionModel. In
* ExpressionModel, tidy and tidyExpressionModel trigger the same
diff --git a/apps/shared/expression_model_list_controller.cpp b/apps/shared/expression_model_list_controller.cpp
index dc1c18d0f52..3defcde2e2e 100644
--- a/apps/shared/expression_model_list_controller.cpp
+++ b/apps/shared/expression_model_list_controller.cpp
@@ -184,18 +184,19 @@ bool ExpressionModelListController::handleEventOnExpression(Ion::Events::Event e
}
if (event == Ion::Events::Backspace && !isAddEmptyRow(selectedRow())) {
Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(selectedRow()));
- ExpiringPointer model = modelStore()->modelForRecord(record);
- if (model->shouldBeClearedBeforeRemove()) {
- reinitSelectedExpression(model);
- } else {
- if (removeModelRow(record)) {
- int newSelectedRow = selectedRow() >= numberOfExpressionRows() ? numberOfExpressionRows()-1 : selectedRow();
- selectCellAtLocation(selectedColumn(), newSelectedRow);
- selectableTableView()->reloadData();
- }
+ ExpiringPointer model = modelStore()->modelForRecord(record);
+ if (removeModelRow(record)) {
+ int newSelectedRow = selectedRow() >= numberOfExpressionRows() ? numberOfExpressionRows()-1 : selectedRow();
+ selectCellAtLocation(selectedColumn(), newSelectedRow);
+ selectableTableView()->reloadData();
}
return true;
}
+ if (event == Ion::Events::ShiftBack) {
+ Ion::Storage::sharedStorage()->reinsertTrash(recordExtension());
+ selectableTableView()->reloadData();
+ return true;
+ }
if ((event.hasText() || event == Ion::Events::XNT || event == Ion::Events::Paste || event == Ion::Events::Toolbox || event == Ion::Events::Var)
&& !isAddEmptyRow(selectedRow())) {
editExpression(event);
diff --git a/apps/shared/expression_model_list_controller.h b/apps/shared/expression_model_list_controller.h
index 45162107c9d..9ced3980a18 100644
--- a/apps/shared/expression_model_list_controller.h
+++ b/apps/shared/expression_model_list_controller.h
@@ -11,6 +11,7 @@ class ExpressionModelListController : public ViewController, public SelectableTa
public:
ExpressionModelListController(Responder * parentResponder, I18n::Message text);
protected:
+ virtual const char * recordExtension() const = 0;
static constexpr KDCoordinate k_expressionMargin = 5;
// SelectableTableViewDelegate
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override;
diff --git a/apps/shared/function.cpp b/apps/shared/function.cpp
index 3f3150d6f14..7248b6b6a71 100644
--- a/apps/shared/function.cpp
+++ b/apps/shared/function.cpp
@@ -55,6 +55,10 @@ void Function::setActive(bool active) {
}
}
+void Function::setColor(KDColor color) {
+ recordData()->setColor(color);
+}
+
int Function::printValue(double cursorT, double cursorX, double cursorY, char * buffer, int bufferSize, int precision, Poincare::Context * context) {
return PoincareHelpers::ConvertFloatToText(cursorY, buffer, bufferSize, precision);
}
diff --git a/apps/shared/function.h b/apps/shared/function.h
index a5daa9c5917..6fa039bac0e 100644
--- a/apps/shared/function.h
+++ b/apps/shared/function.h
@@ -36,6 +36,7 @@ class Function : public ExpressionModelHandle {
bool isActive() const;
KDColor color() const;
void setActive(bool active);
+ void setColor(KDColor color);
// Definition Interval
virtual bool shouldClipTRangeToXRange() const { return true; } // Returns true if the function will not be displayed if t is outside x range.
@@ -76,6 +77,7 @@ class Function : public ExpressionModelHandle {
KDColor color() const {
return KDColor::RGB16(m_color);
}
+ void setColor(KDColor color) { m_color = color; }
bool isActive() const { return m_active; }
void setActive(bool active) { m_active = active; }
private:
diff --git a/apps/shared/function_app.cpp b/apps/shared/function_app.cpp
index fbdc4f43aeb..a63ca328430 100644
--- a/apps/shared/function_app.cpp
+++ b/apps/shared/function_app.cpp
@@ -31,9 +31,13 @@ void FunctionApp::willBecomeInactive() {
::App::willBecomeInactive();
}
-
-bool FunctionApp::isAcceptableExpression(const Expression exp) {
- return TextFieldDelegateApp::isAcceptableExpression(exp) && ExpressionCanBeSerialized(exp, false, Expression(), localContext());
+bool FunctionApp::isAcceptableExpression(const Poincare::Expression expression) {
+ /* We forbid functions whose type is equal because the input "2+f(3)" would be
+ * simplify to an expression with an nested equal node which makes no sense. */
+ if (!TextFieldDelegateApp::ExpressionCanBeSerialized(expression, false, Expression(), localContext()) || expression.type() == ExpressionNode::Type::Equal) {
+ return false;
+ }
+ return TextFieldDelegateApp::isAcceptableExpression(expression);
}
}
diff --git a/apps/shared/function_curve_parameter_controller.h b/apps/shared/function_curve_parameter_controller.h
index 96e8668445f..a720e2e9d39 100644
--- a/apps/shared/function_curve_parameter_controller.h
+++ b/apps/shared/function_curve_parameter_controller.h
@@ -16,7 +16,7 @@ class FunctionCurveParameterController : public ViewController, public SimpleLis
void setRecord(Ion::Storage::Record record) { m_record = record; }
protected:
bool handleGotoSelection();
- MessageTableCellWithChevron m_goToCell;
+ MessageTableCellWithChevron<> m_goToCell;
SelectableTableView m_selectableTableView;
Ion::Storage::Record m_record;
private:
diff --git a/apps/shared/function_list_controller.cpp b/apps/shared/function_list_controller.cpp
index d8dbf2ad7a3..4083ab9551d 100644
--- a/apps/shared/function_list_controller.cpp
+++ b/apps/shared/function_list_controller.cpp
@@ -200,6 +200,11 @@ bool FunctionListController::handleEvent(Ion::Events::Event event) {
}
return true;
}
+ if (event == Ion::Events::ShiftBack) {
+ Ion::Storage::sharedStorage()->reinsertTrash(recordExtension());
+ selectableTableView()->reloadData();
+ return true;
+ }
return false;
}
diff --git a/apps/shared/function_list_controller.h b/apps/shared/function_list_controller.h
index da6a7036a26..be62a843544 100644
--- a/apps/shared/function_list_controller.h
+++ b/apps/shared/function_list_controller.h
@@ -7,6 +7,7 @@
#include "list_parameter_controller.h"
#include "expression_model_list_controller.h"
#include
+#include
namespace Shared {
diff --git a/apps/shared/global_context.cpp b/apps/shared/global_context.cpp
index 5df9889538f..0bf41617540 100644
--- a/apps/shared/global_context.cpp
+++ b/apps/shared/global_context.cpp
@@ -128,20 +128,27 @@ const Expression GlobalContext::ExpressionForSequence(const SymbolAbstract & sym
if (!rank.isUninitialized()) {
bool rankIsInteger = false;
double rankValue = rank.approximateToScalar(ctx, Poincare::Preferences::sharedPreferences()->complexFormat(), Poincare::Preferences::sharedPreferences()->angleUnit());
+ int rankValueFloor = std::floor(rankValue);
if (rank.type() == ExpressionNode::Type::Rational) {
Rational n = static_cast(rank);
rankIsInteger = n.isInteger();
} else if (!std::isnan(unknownSymbolValue)) {
/* If unknownSymbolValue is not nan, then we are in the graph app. In order
* to allow functions like f(x) = u(x+0.5) to be ploted, we need to
- * approximate the rank and check if it is an integer. Unfortunatly this
+ * approximate the rank and check if it is an integer. Unfortunately this
* leads to some edge cases were, because of quantification, we have
* floor(x) = x while x is not integer.*/
- rankIsInteger = std::floor(rankValue) == rankValue;
+ rankIsInteger = rankValueFloor == rankValue;
}
- if (rankIsInteger && !seq.badlyReferencesItself(ctx)) {
- SequenceContext sqctx(ctx, sequenceStore());
- return Float::Builder(seq.evaluateXYAtParameter(rankValue, &sqctx).x2());
+ if (rankIsInteger) {
+ if (rankValueFloor - seq.initialRank() < (int) seq.type()) { // Seq can reference itself but be defined explicitly for first values
+ assert(rankValueFloor - seq.initialRank() == 0 || rankValueFloor - seq.initialRank() == 1);
+ return rankValueFloor - seq.initialRank() == 0 ? seq.firstInitialConditionExpressionClone() : seq.secondInitialConditionExpressionClone();
+ }
+ if (!seq.badlyReferencesItself(ctx)) {
+ SequenceContext sqctx(ctx, sequenceStore());
+ return Float::Builder(seq.evaluateXYAtParameter(rankValue, &sqctx).x2());
+ }
}
}
return Float::Builder(NAN);
diff --git a/apps/shared/layout_field_delegate.h b/apps/shared/layout_field_delegate.h
index 79f25607d6a..5b2bb1c3c5e 100644
--- a/apps/shared/layout_field_delegate.h
+++ b/apps/shared/layout_field_delegate.h
@@ -2,11 +2,13 @@
#define SHARED_LAYOUT_FIELD_DELEGATE_H
#include "expression_field_delegate_app.h"
+#include "../apps_container.h"
namespace Shared {
class LayoutFieldDelegate : public ::LayoutFieldDelegate {
public:
+ void layoutFieldDidReceiveNoneXNTEvent() override { AppsContainer::sharedAppsContainer()->resetXNT(); }
bool layoutFieldShouldFinishEditing(LayoutField * layoutField, Ion::Events::Event event) override;
bool layoutFieldDidReceiveEvent(LayoutField * layoutField, Ion::Events::Event event) override;
bool layoutFieldDidFinishEditing(LayoutField * layoutField, Poincare::Layout layoutR, Ion::Events::Event event) override;
diff --git a/apps/shared/list_parameter_controller.cpp b/apps/shared/list_parameter_controller.cpp
index 27c11745f71..e55e3bf2a8d 100644
--- a/apps/shared/list_parameter_controller.cpp
+++ b/apps/shared/list_parameter_controller.cpp
@@ -8,12 +8,12 @@ ListParameterController::ListParameterController(Responder * parentResponder, I1
ViewController(parentResponder),
m_selectableTableView(this, this, this, tableDelegate),
m_record(),
-#if FUNCTION_COLOR_CHOICE
- m_colorCell(functionColorMessage),
-#endif
+ m_colorCell(),
m_enableCell(I18n::Message::ActivateDeactivate),
- m_deleteCell(deleteFunctionMessage)
+ m_deleteCell(deleteFunctionMessage),
+ m_colorParameterController(parentResponder, functionColorMessage)
{
+ m_colorCell.setMessage(functionColorMessage);
}
const char * ListParameterController::title() {
@@ -38,6 +38,16 @@ void ListParameterController::willDisplayCellForIndex(HighlightCell * cell, int
if (cell == &m_enableCell) {
SwitchView * switchView = (SwitchView *)m_enableCell.accessoryView();
switchView->setState(function()->isActive());
+ } else if(cell == &m_colorCell) {
+ int index = -1;
+ KDColor color = function()->color();
+ for(int i = 0; i < Palette::numberOfDataColors(); i++) {
+ if(color == Palette::DataColor[i]) {
+ index = i;
+ }
+ }
+ assert(index >= 0);
+ m_colorCell.setSubtitle(MessageTableCellWithColor::k_textForIndex[index]);
}
}
@@ -64,11 +74,7 @@ int ListParameterController::indexFromCumulatedHeight(KDCoordinate offsetY) {
HighlightCell * ListParameterController::reusableCell(int index, int type) {
assert(index == 0);
assert(index < totalNumberOfCells());
-#if FUNCTION_COLOR_CHOICE
HighlightCell * cells[] = {&m_colorCell, &m_enableCell, &m_deleteCell};
-#else
- HighlightCell * cells[] = {&m_enableCell, &m_deleteCell};
-#endif
return cells[type];
}
@@ -78,22 +84,17 @@ int ListParameterController::typeAtLocation(int i, int j) {
bool ListParameterController::handleEnterOnRow(int rowIndex) {
switch (rowIndex) {
-#if FUNCTION_COLOR_CHOICE
- case 0:
- /* TODO: implement function color choice */
+ case 0: {
+ StackViewController * stack = (StackViewController *)(parentResponder());
+ m_colorParameterController.setRecord(m_record);
+ stack->push(&m_colorParameterController);
return true;
+ }
case 1:
-#else
- case 0:
-#endif
function()->setActive(!function()->isActive());
m_selectableTableView.reloadData();
return true;
-#if FUNCTION_COLOR_CHOICE
- case 2:
-#else
- case 1:
-#endif
+ case 2:
{
assert(functionStore()->numberOfModels() > 0);
functionStore()->removeModel(m_record);
diff --git a/apps/shared/list_parameter_controller.h b/apps/shared/list_parameter_controller.h
index 4ef2b616ec4..d948073bb6f 100644
--- a/apps/shared/list_parameter_controller.h
+++ b/apps/shared/list_parameter_controller.h
@@ -3,6 +3,7 @@
#include
#include "function_store.h"
+#include "color_parameter_controller.h"
#include
namespace Shared {
@@ -31,22 +32,17 @@ class ListParameterController : public ViewController, public ListViewDataSource
protected:
virtual bool handleEnterOnRow(int rowIndex);
virtual int totalNumberOfCells() const {
-#if FUNCTION_COLOR_CHOICE
return 3;
-#else
- return 2;
-#endif
}
FunctionStore * functionStore();
ExpiringPointer function();
SelectableTableView m_selectableTableView;
Ion::Storage::Record m_record;
private:
-#if FUNCTION_COLOR_CHOICE
- MessageTableCellWithChevron m_colorCell;
-#endif
+ MessageTableCellWithChevronAndMessage m_colorCell;
MessageTableCellWithSwitch m_enableCell;
- MessageTableCell m_deleteCell;
+ MessageTableCell<> m_deleteCell;
+ ColorParameterController m_colorParameterController;
};
}
diff --git a/apps/shared/localization_controller.cpp b/apps/shared/localization_controller.cpp
index f518999b3ef..b1476aa3dcf 100644
--- a/apps/shared/localization_controller.cpp
+++ b/apps/shared/localization_controller.cpp
@@ -18,7 +18,7 @@ LocalizationController::ContentView::ContentView(LocalizationController * contro
assert(k_numberOfCountryWarningLines == 2); // textMessages is not overflowed
I18n::Message textMessages[k_numberOfCountryWarningLines] = {I18n::Message::CountryWarning1, I18n::Message::CountryWarning2};
for (int i = 0; i < k_numberOfCountryWarningLines; i++) {
- m_countryWarningLines[i].setBackgroundColor(Palette::BackgroundHard);
+ m_countryWarningLines[i].setBackgroundColor(Palette::BackgroundApps);
m_countryWarningLines[i].setFont(KDFont::SmallFont);
m_countryWarningLines[i].setAlignment(0.5f, 0.5f);
m_countryWarningLines[i].setMessage(textMessages[i]);
@@ -191,10 +191,10 @@ bool LocalizationController::handleEvent(Ion::Events::Event event) {
void LocalizationController::willDisplayCellForIndex(HighlightCell * cell, int index) {
if (mode() == Mode::Language) {
- static_cast(cell)->setMessage(I18n::LanguageNames[index]);
+ static_cast *>(cell)->setMessage(I18n::LanguageNames[index]);
return;
}
assert(mode() == Mode::Country);
- static_cast(cell)->setMessage(I18n::CountryNames[static_cast(CountryAtIndex(index))]);
+ static_cast *>(cell)->setMessage(I18n::CountryNames[static_cast(CountryAtIndex(index))]);
}
}
diff --git a/apps/shared/localization_controller.h b/apps/shared/localization_controller.h
index 327d3ef5d3c..ddc8c1d08da 100644
--- a/apps/shared/localization_controller.h
+++ b/apps/shared/localization_controller.h
@@ -71,7 +71,7 @@ class LocalizationController : public ViewController, public SimpleListViewDataS
private:
static constexpr int k_numberOfCells = I18n::NumberOfLanguages > I18n::NumberOfCountries ? I18n::NumberOfLanguages : I18n::NumberOfCountries;
- MessageTableCell m_cells[k_numberOfCells];
+ MessageTableCell<> m_cells[k_numberOfCells];
Mode m_mode;
};
diff --git a/apps/shared/message_view.cpp b/apps/shared/message_view.cpp
index 3bc257ab0f4..05975da8e95 100644
--- a/apps/shared/message_view.cpp
+++ b/apps/shared/message_view.cpp
@@ -1,13 +1,14 @@
#include "message_view.h"
#include
-MessageView::MessageView(I18n::Message * messages, KDColor * colors, uint8_t numberOfMessages) {
+MessageView::MessageView(I18n::Message * messages, KDColor * fgcolors, KDColor * bgcolors, uint8_t numberOfMessages) {
m_numberOfMessages = numberOfMessages < k_maxNumberOfMessages ? numberOfMessages : k_maxNumberOfMessages;
for (uint8_t i = 0; i < m_numberOfMessages; i++) {
m_messageTextViews[i].setFont(i == 0 ? KDFont::LargeFont : KDFont::SmallFont);
m_messageTextViews[i].setMessage(messages[i]);
m_messageTextViews[i].setAlignment(0.5f, 0.5f);
- m_messageTextViews[i].setTextColor(colors[i]);
+ m_messageTextViews[i].setTextColor(fgcolors[i]);
+ m_messageTextViews[i].setBackgroundColor(bgcolors[i]);
}
}
diff --git a/apps/shared/message_view.h b/apps/shared/message_view.h
index 41fb9e648a1..f6b773e95dd 100644
--- a/apps/shared/message_view.h
+++ b/apps/shared/message_view.h
@@ -5,7 +5,7 @@
class MessageView : public View {
public:
- MessageView(I18n::Message * messages, KDColor * colors, uint8_t numberOfMessages);
+ MessageView(I18n::Message * messages, KDColor * fgcolors, KDColor * bgcolors, uint8_t numberOfMessages);
void drawRect(KDContext * ctx, KDRect rect) const override;
protected:
int numberOfSubviews() const override { return m_numberOfMessages; }
diff --git a/apps/shared/scrollable_multiple_expressions_view.cpp b/apps/shared/scrollable_multiple_expressions_view.cpp
index 5d0331f5422..49021e1a888 100644
--- a/apps/shared/scrollable_multiple_expressions_view.cpp
+++ b/apps/shared/scrollable_multiple_expressions_view.cpp
@@ -24,13 +24,13 @@ void AbstractScrollableMultipleExpressionsView::ContentCell::setHighlighted(bool
// Do not call HighlightCell::setHighlighted to avoid marking all cell as dirty
m_highlighted = highlight;
KDColor defaultColor = backgroundColor();
- KDColor color = highlight && m_selectedSubviewPosition == SubviewPosition::Center ? Palette::ExpressionInputBackground : defaultColor;
+ KDColor color = highlight && m_selectedSubviewPosition == SubviewPosition::Center ? Palette::Select : defaultColor;
m_centeredExpressionView.setBackgroundColor(color);
- color = highlight && m_selectedSubviewPosition == SubviewPosition::Right ? Palette::ExpressionInputBackground : defaultColor;
+ color = highlight && m_selectedSubviewPosition == SubviewPosition::Right ? Palette::Select : defaultColor;
m_rightExpressionView.setBackgroundColor(color);
m_approximateSign.setBackgroundColor(defaultColor);
if (leftExpressionView()) {
- color = highlight && m_selectedSubviewPosition == SubviewPosition::Left ? Palette::ExpressionInputBackground : defaultColor;
+ color = highlight && m_selectedSubviewPosition == SubviewPosition::Left ? Palette::Select : defaultColor;
leftExpressionView()->setBackgroundColor(color);
}
}
diff --git a/apps/shared/sequence_context.h b/apps/shared/sequence_context.h
index 83c8d8e9f04..f2995a58e82 100644
--- a/apps/shared/sequence_context.h
+++ b/apps/shared/sequence_context.h
@@ -62,7 +62,7 @@ class SequenceContext : public Poincare::ContextWithParent {
m_sequenceStore(sequenceStore) {}
/* expressionForSymbolAbstract & setExpressionForSymbolAbstractName directly call the parent
* context respective methods. Indeed, special chars like n, u(n), u(n+1),
- * v(n), v(n+1) are taken into accound only when evaluating sequences which
+ * v(n), v(n+1) are taken into account only when evaluating sequences which
* is done in another context. */
template T valueOfCommonRankSequenceAtPreviousRank(int sequenceIndex, int rank) {
return static_cast*>(helper())->valueOfCommonRankSequenceAtPreviousRank(sequenceIndex, rank);
diff --git a/apps/shared/store_controller.cpp b/apps/shared/store_controller.cpp
index ee4244f3bbd..ebabb133983 100644
--- a/apps/shared/store_controller.cpp
+++ b/apps/shared/store_controller.cpp
@@ -232,7 +232,7 @@ bool StoreController::privateFillColumnWithFormula(Expression formula, Expressio
variables[0][0] = 0;
AppsContainer * appsContainer = AppsContainer::sharedAppsContainer();
int nbOfVariables = formula.getVariables(appsContainer->globalContext(), isVariable, (char *)variables, k_maxSizeOfStoreSymbols);
- (void) nbOfVariables; // Remove compilation warning of nused variable
+ (void) nbOfVariables; // Remove compilation warning of unused variable
assert(nbOfVariables >= 0);
int numberOfValuesToCompute = -1;
int index = 0;
diff --git a/apps/shared/store_controller.h b/apps/shared/store_controller.h
index 1083f8201f5..d0eebb316cb 100644
--- a/apps/shared/store_controller.h
+++ b/apps/shared/store_controller.h
@@ -49,7 +49,12 @@ class StoreController : public EditableCellTableViewController, public ButtonRow
static constexpr KDCoordinate k_cellWidth = Poincare::PrintFloat::glyphLengthForFloatWithPrecision(Poincare::Preferences::LargeNumberOfSignificantDigits) * 7 + 2*Metric::CellMargin + Metric::TableSeparatorThickness; // KDFont::SmallFont->glyphSize().width() = 7
constexpr static int k_maxNumberOfEditableCells = (Ion::Display::Width/k_cellWidth+2) * ((Ion::Display::Height - Metric::TitleBarHeight - Metric::TabHeight)/k_cellHeight+2);
+ #ifndef _FXCG
constexpr static int k_numberOfTitleCells = 4;
+ #else
+ // This is different here due to the changed screen resolution
+ constexpr static int k_numberOfTitleCells = 5;
+ #endif
static constexpr int k_titleCellType = 0;
static constexpr int k_editableCellType = 1;
diff --git a/apps/shared/store_parameter_controller.h b/apps/shared/store_parameter_controller.h
index efc8c6f1273..4302efcc84a 100644
--- a/apps/shared/store_parameter_controller.h
+++ b/apps/shared/store_parameter_controller.h
@@ -41,7 +41,7 @@ class StoreParameterController : public ViewController, public ListViewDataSourc
private:
virtual I18n::Message sortMessage() { return m_xColumnSelected ? I18n::Message::SortValues : I18n::Message::SortSizes; }
constexpr static int k_totalNumberOfCell = 3;
- MessageTableCell m_cells[k_totalNumberOfCell];
+ MessageTableCell<> m_cells[k_totalNumberOfCell];
StoreController * m_storeController;
bool m_xColumnSelected;
};
diff --git a/apps/shared/sum_graph_controller.cpp b/apps/shared/sum_graph_controller.cpp
index 423582e900c..08ddd6926b4 100644
--- a/apps/shared/sum_graph_controller.cpp
+++ b/apps/shared/sum_graph_controller.cpp
@@ -232,12 +232,12 @@ void SumGraphController::LegendView::layoutSubviews(bool force) {
void SumGraphController::LegendView::layoutSubviews(Step step, bool force) {
KDCoordinate width = bounds().width();
- KDCoordinate heigth = bounds().height();
+ KDCoordinate height = bounds().height();
KDSize legendSize = m_legend.minimalSizeForOptimalDisplay();
if (legendSize.width() > 0) {
m_sum.setFrame(KDRect(0, k_symbolHeightMargin, width-legendSize.width(), m_sum.minimalSizeForOptimalDisplay().height()), force);
- m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), heigth), force);
+ m_legend.setFrame(KDRect(width-legendSize.width(), 0, legendSize.width(), height), force);
} else {
m_sum.setFrame(bounds(), force);
m_legend.setFrame(KDRectZero, force);
diff --git a/apps/shared/text_field_delegate.h b/apps/shared/text_field_delegate.h
index bc148e95a6c..cd04bcffb6c 100644
--- a/apps/shared/text_field_delegate.h
+++ b/apps/shared/text_field_delegate.h
@@ -2,11 +2,13 @@
#define SHARED_TEXT_FIELD_DELEGATE_H
#include "text_field_delegate_app.h"
+#include "../apps_container.h"
namespace Shared {
class TextFieldDelegate : public ::TextFieldDelegate {
public:
+ void textFieldDidReceiveNoneXNTEvent() override { AppsContainer::sharedAppsContainer()->resetXNT(); }
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
protected:
diff --git a/apps/shared/text_field_delegate_app.cpp b/apps/shared/text_field_delegate_app.cpp
index e66a874224d..68ae84d0b3e 100644
--- a/apps/shared/text_field_delegate_app.cpp
+++ b/apps/shared/text_field_delegate_app.cpp
@@ -72,10 +72,12 @@ bool TextFieldDelegateApp::fieldDidReceiveEvent(EditableField * field, Responder
if (XNTCanBeOverriden()) {
xnt = field->XNTCodePoint(xnt);
}
+ bool shouldRemoveLastCharacter = false;
+ xnt = AppsContainer::sharedAppsContainer()->XNT(xnt, &shouldRemoveLastCharacter);
size_t length = UTF8Decoder::CodePointToChars(xnt, buffer, bufferSize);
assert(length < bufferSize - 1);
buffer[length] = 0;
- return field->handleEventWithText(buffer);
+ return field->handleEventWithText(buffer, false, false, shouldRemoveLastCharacter);
}
return false;
}
@@ -85,7 +87,13 @@ bool TextFieldDelegateApp::isFinishingEvent(Ion::Events::Event event) {
}
bool TextFieldDelegateApp::isAcceptableExpression(const Expression exp) {
- return !(exp.isUninitialized() || exp.type() == ExpressionNode::Type::Store || exp.type() == ExpressionNode::Type::Equal);
+ if (exp.isUninitialized()) {
+ return false;
+ }
+ if (exp.type() == ExpressionNode::Type::Store) {
+ return false;
+ }
+ return true;
}
bool TextFieldDelegateApp::ExpressionCanBeSerialized(const Expression expression, bool replaceAns, Expression ansExpression, Context * context) {
diff --git a/apps/shared/text_field_delegate_app.h b/apps/shared/text_field_delegate_app.h
index 0dd472e78e4..a33adffde77 100644
--- a/apps/shared/text_field_delegate_app.h
+++ b/apps/shared/text_field_delegate_app.h
@@ -5,6 +5,7 @@
#include "input_event_handler_delegate_app.h"
#include