[omega] 1.20.0

This commit is contained in:
Quentin Guidée
2020-07-20 17:09:03 +02:00
889 changed files with 38840 additions and 7531 deletions

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1 @@
blank_issues_enabled: false

View File

@@ -2,7 +2,25 @@ name: Continuous integration
on: [pull_request, push] on: [pull_request, push]
jobs: jobs:
build-simulator-android: # nintendo_3ds:
# runs-on: ubuntu-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: make -j2 PLATFORM=simulator TARGET=3ds
# - uses: actions/upload-artifact@master
# with:
# name: epsilon-3ds.3dsx
# path: output/release/simulator/3ds/epsilon.3dsx
android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
@@ -11,9 +29,9 @@ jobs:
- run: make -j2 PLATFORM=simulator TARGET=android - run: make -j2 PLATFORM=simulator TARGET=android
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: epsilon-simulator-android.apk name: epsilon-android.apk
path: output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk path: output/release/simulator/android/epsilon.apk
build-device-n0100: n0100:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
@@ -21,18 +39,40 @@ jobs:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
with: with:
submodules: true submodules: true
- run: make -j2 MODEL=n0100 epsilon.dfu - run: mkdir final-output
- run: make -j2 MODEL=n0100 epsilon.onboarding.dfu - run: make -j2 MODEL=n0100 EPSILON_I18N=en output/release/device/n0100/epsilon.onboarding.two_binaries
- run: make -j2 MODEL=n0100 epsilon.onboarding.update.dfu - run: mv output/release/device/n0100/epsilon.onboarding.internal.bin final-output/epsilon.onboarding.internal.en.bin
- run: make -j2 MODEL=n0100 epsilon.onboarding.beta.dfu - run: rm output/release/device/n0100/apps/i18n.o output/release/device/n0100/apps/i18n.cpp
- run: make -j2 MODEL=n0100 flasher.light.dfu - run: make -j2 MODEL=n0100 EPSILON_I18N=fr output/release/device/n0100/epsilon.onboarding.two_binaries
- run: make -j2 MODEL=n0100 flasher.verbose.dfu - run: mv output/release/device/n0100/epsilon.onboarding.internal.bin final-output/epsilon.onboarding.internal.fr.bin
- run: rm output/release/device/n0100/apps/i18n.o output/release/device/n0100/apps/i18n.cpp
- run: make -j2 MODEL=n0100 EPSILON_I18N=nl output/release/device/n0100/epsilon.onboarding.two_binaries
- run: mv output/release/device/n0100/epsilon.onboarding.internal.bin final-output/epsilon.onboarding.internal.nl.bin
- run: rm output/release/device/n0100/apps/i18n.o output/release/device/n0100/apps/i18n.cpp
- run: make -j2 MODEL=n0100 EPSILON_I18N=pt output/release/device/n0100/epsilon.onboarding.two_binaries
- run: mv output/release/device/n0100/epsilon.onboarding.internal.bin final-output/epsilon.onboarding.internal.pt.bin
- run: rm output/release/device/n0100/apps/i18n.o output/release/device/n0100/apps/i18n.cpp
- run: make -j2 MODEL=n0100 EPSILON_I18N=it output/release/device/n0100/epsilon.onboarding.two_binaries
- run: mv output/release/device/n0100/epsilon.onboarding.internal.bin final-output/epsilon.onboarding.internal.it.bin
- run: rm output/release/device/n0100/apps/i18n.o output/release/device/n0100/apps/i18n.cpp
- run: make -j2 MODEL=n0100 EPSILON_I18N=de output/release/device/n0100/epsilon.onboarding.two_binaries
- run: mv output/release/device/n0100/epsilon.onboarding.internal.bin final-output/epsilon.onboarding.internal.de.bin
- run: rm output/release/device/n0100/apps/i18n.o output/release/device/n0100/apps/i18n.cpp
- run: make -j2 MODEL=n0100 EPSILON_I18N=es output/release/device/n0100/epsilon.onboarding.two_binaries
- run: mv output/release/device/n0100/epsilon.onboarding.internal.bin final-output/epsilon.onboarding.internal.es.bin
- run: rm output/release/device/n0100/apps/i18n.o output/release/device/n0100/apps/i18n.cpp
- run: make -j2 MODEL=n0100 EPSILON_I18N=hu output/release/device/n0100/epsilon.onboarding.two_binaries
- run: mv output/release/device/n0100/epsilon.onboarding.internal.bin final-output/epsilon.onboarding.internal.hu.bin
- run: rm output/release/device/n0100/apps/i18n.o output/release/device/n0100/apps/i18n.cpp
- run: make -j2 MODEL=n0100 output/release/device/n0100/flasher.light.bin
- 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/*
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: epsilon-device-n0100.dfu name: epsilon-binpack-n0100.tgz
path: output/release/device/n0100/epsilon.dfu path: binpack-n0100.tgz
- run: make -j2 MODEL=n0100 test.elf n0110:
build-device-n0110:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
@@ -48,12 +88,13 @@ jobs:
- run: make -j2 flasher.verbose.dfu - run: make -j2 flasher.verbose.dfu
- run: make -j2 bench.ram.dfu - run: make -j2 bench.ram.dfu
- run: make -j2 bench.flash.dfu - run: make -j2 bench.flash.dfu
- run: make -j2 binpack
- run: cp output/release/device/n0110/binpack-n0110-`git rev-parse HEAD | head -c 7`.tgz output/release/device/n0110/binpack-n0110.tgz
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: epsilon-device-n0110.dfu name: epsilon-binpack-n0110.tgz
path: output/release/device/n0110/epsilon.dfu path: output/release/device/n0110/binpack-n0110.tgz
- run: make -j2 test.elf web:
build-simulator-web:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: numworks/setup-emscripten@v2 - uses: numworks/setup-emscripten@v2
@@ -65,10 +106,9 @@ jobs:
- run: make -j2 PLATFORM=simulator TARGET=web - run: make -j2 PLATFORM=simulator TARGET=web
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: epsilon-simulator-web.zip name: epsilon-web.zip
path: output/release/simulator/web/epsilon.zip path: output/release/simulator/web/epsilon.zip
- run: make -j2 PLATFORM=simulator TARGET=web test.headless.js linux:
build-simulator-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config - run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
@@ -78,6 +118,6 @@ jobs:
- run: make -j2 PLATFORM=simulator - run: make -j2 PLATFORM=simulator
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: epsilon-simulator-linux.bin name: epsilon-linux.bin
path: output/release/simulator/linux/epsilon.bin path: output/release/simulator/linux/epsilon.bin
- run: make -j2 PLATFORM=simulator test.headless.bin - run: make -j2 PLATFORM=simulator test.headless.bin

38
.github/workflows/metric-workflow.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: Metrics
on: [pull_request]
jobs:
binary-size:
runs-on: ubuntu-latest
steps:
- name: Install dependencies
run: sudo apt-get install build-essential imagemagick libfreetype6-dev libjpeg-dev libpng-dev pkg-config
- name: Install ARM toolchain
uses: numworks/setup-arm-toolchain@v1
- name: Checkout PR base
uses: actions/checkout@v2
with:
submodules: recursive
ref: ${{ github.event.pull_request.base.sha }}
path: base
- name: Build base
run: make -j2 -C base epsilon.elf
- name: Checkout PR head
uses: actions/checkout@v2
with:
submodules: recursive
ref: ${{ github.event.pull_request.head.sha }}
path: head
- name: Build head
run: make -j2 -C head 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: Prepare comment auth
run: echo "::set-env name=GITHUB_TOKEN::$(echo YjgxYTk1YTQ4YzYxNjU4ZTA3YWQzNDYwNTk3ZTI2MTlkODU5MThlOQo= | base64 --decode)"
- name: Add comment
uses: actions/github@v1.0.0
env:
GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }}
with:
args: comment ${{ steps.binary_size.outputs.table }}

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
/build/artifacts/ /build/artifacts/
build/device/**/*.pyc build/device/**/*.pyc
epsilon.elf epsilon.elf
epsilon.map
.vscode .vscode
.DS_Store .DS_Store
.gradle .gradle

76
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at getomega.pro@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View File

@@ -1,4 +1,16 @@
# Disable default Make rules
.SUFFIXES:
# Define the default recipe
default:
include build/config.mak include build/config.mak
include build/pimp.mak
include build/defaults.mak
include build/platform.$(PLATFORM).mak
include build/toolchain.$(TOOLCHAIN).mak
include build/variants.mak
include build/helpers.mk
ifeq (${MODEL}, n0110) ifeq (${MODEL}, n0110)
apps_list = ${EPSILON_APPS} apps_list = ${EPSILON_APPS}
@@ -10,42 +22,21 @@ ifdef FORCE_EXTERNAL
apps_list = ${EPSILON_APPS} apps_list = ${EPSILON_APPS}
endif endif
# Disable default Make rules ifdef HOME_DISPLAY_EXTERNALS
.SUFFIXES: ifneq ($(filter external,$(apps_list)),)
SFLAGS += -DHOME_DISPLAY_EXTERNALS
object_for = $(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(basename $(1)))) else
$(warning HOME_DISPLAY_EXTERNALS is set but external isn't included, ignoring flag.)
# Define the default recipe endif
default:
# Define a standard rule helper
# If passed a last parameter value of with_local_version, we also define an
# extra rule that can build source files within the $(BUILD_DIR). This is useful
# for rules that can be applied for intermediate objects (for example, when
# going .png -> .cpp -> .o).
define rule_label
@ echo "$(shell printf "%-8s" $(strip $(1)))$(@:$(BUILD_DIR)/%=%)"
endef
define rule_for
ifeq ($(strip $(5)),with_local_version)
$(addprefix $$(BUILD_DIR)/,$(strip $(2))): $(addprefix $$(BUILD_DIR)/,$(strip $(3))) | $(if $(findstring official,${MAKECMDGOALS}),official_authorization)
@ echo "$(shell printf "%-8s" $(strip $(1)))$$(@:$$(BUILD_DIR)/%=%)"
$(Q) $(4)
endif endif
$(addprefix $$(BUILD_DIR)/,$(strip $(2))): $(strip $(3)) | $$$$(@D)/. $(if $(findstring official,${MAKECMDGOALS}),official_authorization)
@ echo "$(shell printf "%-8s" $(strip $(1)))$$(@:$$(BUILD_DIR)/%=%)"
$(Q) $(4)
endef
.PHONY: info .PHONY: info
info: info:
@echo "EPSILON_VERSION = $(EPSILON_VERSION)" @echo "EPSILON_VERSION = $(EPSILON_VERSION)"
@echo "EPSILON_APPS = $(EPSILON_APPS)" @echo "EPSILON_APPS = $(EPSILON_APPS)"
@echo "EPSILON_I18N = $(EPSILON_I18N)" @echo "EPSILON_I18N = $(EPSILON_I18N)"
@echo "OMEGA_THEME = $(OMEGA_THEME)" @echo "THEME_NAME = $(THEME_NAME)"
@echo "THEME_REPO = $(THEME_REPO)"
@echo "BUILD_DIR = $(BUILD_DIR)" @echo "BUILD_DIR = $(BUILD_DIR)"
@echo "PLATFORM" = $(PLATFORM) @echo "PLATFORM" = $(PLATFORM)
@echo "DEBUG" = $(DEBUG) @echo "DEBUG" = $(DEBUG)
@@ -78,6 +69,7 @@ help:
@echo " make PLATFORM=simulator TARGET=macos" @echo " make PLATFORM=simulator TARGET=macos"
@echo " make PLATFORM=simulator TARGET=web" @echo " make PLATFORM=simulator TARGET=web"
@echo " make PLATFORM=simulator TARGET=windows" @echo " make PLATFORM=simulator TARGET=windows"
@echo " make PLATFORM=simulator TARGET=3ds"
.PHONY: doc .PHONY: doc
doc: doc:
@@ -107,7 +99,9 @@ $(BUILD_DIR)%/.:
# Each sub-Makefile can either add sources to $(%_src) variables or define a # Each sub-Makefile can either add sources to $(%_src) variables or define a
# new executable target. The $(%_src) variables list the sources that can be # new executable target. The $(%_src) variables list the sources that can be
# built and linked to executables being generated. # built and linked to executables being generated.
ifndef USE_LIBA
$(error platform.mak should define USE_LIBA)
endif
ifeq ($(USE_LIBA),0) ifeq ($(USE_LIBA),0)
include liba/Makefile.bridge include liba/Makefile.bridge
else else
@@ -126,10 +120,10 @@ include build/struct_layout/Makefile
include build/scenario/Makefile include build/scenario/Makefile
include quiz/Makefile # Quiz needs to be included at the end include quiz/Makefile # Quiz needs to be included at the end
all_src = $(apps_all_src) $(escher_src) $(ion_all_src) $(kandinsky_src) $(liba_src) $(libaxx_src) $(poincare_src) $(python_src) $(runner_src) $(ion_target_device_flasher_light_src) $(ion_target_device_flasher_verbose_src) $(ion_target_device_bench_src) $(tests_src) all_src = $(apps_src) $(escher_src) $(ion_src) $(kandinsky_src) $(liba_src) $(libaxx_src) $(poincare_src) $(python_src) $(runner_src) $(ion_device_flasher_src) $(ion_device_bench_src) $(tests_src)
# Make palette.h a dep for every source-file. # Make palette.h a dep for every source-file.
# This ensures that the theming engine works correctly. # This ensures that the theming engine works correctly.
$(call object_for,$(all_app_src)): $(BUILD_DIR)/escher/palette.h $(call object_for,$(all_src)): $(BUILD_DIR)/escher/palette.h $(BUILD_DIR)/apps/i18n.h
all_objs = $(call object_for,$(all_src)) all_objs = $(call object_for,$(all_src))
.SECONDARY: $(all_objs) .SECONDARY: $(all_objs)
@@ -144,8 +138,7 @@ all_objs = $(call object_for,$(all_src))
include build/targets.mak include build/targets.mak
# Fill in the default recipe # Fill in the default recipe
DEFAULT ?= $(BUILD_DIR)/epsilon.$(EXE) default: $(firstword $(HANDY_TARGETS)).$(firstword $(HANDY_TARGETS_EXTENSIONS))
default: $(DEFAULT)
# Load standard build rules # Load standard build rules
include build/rules.mk include build/rules.mk

View File

@@ -1,10 +1,10 @@
<p align="center"><img src="https://github.com/Omega-Numworks/Omega-Design/blob/master/Omega-Banner.png" /></p> <p align="center"><img src="https://user-images.githubusercontent.com/12123721/87953533-75a22380-caab-11ea-8cde-c40291c4a9ae.png" /></p>
<p align="center"> <p align="center">
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="cc by-nc-sa 4.0" src="https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-525252.svg?labelColor=292929&logo=creative%20commons&style=for-the-badge" /></a> <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="cc by-nc-sa 4.0" src="https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-525252.svg?labelColor=292929&logo=creative%20commons&style=for-the-badge" /></a>
<a href="https://github.com/Omega-Numworks/Omega/issues"><img alt="Issues" src="https://img.shields.io/github/issues/Omega-Numworks/Omega.svg?labelColor=292929&logo=git&style=for-the-badge" /></a> <a href="https://github.com/Omega-Numworks/Omega/issues"><img alt="Issues" src="https://img.shields.io/github/issues/Omega-Numworks/Omega.svg?labelColor=292929&logo=git&style=for-the-badge" /></a>
<br/> <br/>
<a href="https://discord.gg/hjH3gtd"><img alt="Discord" src="https://img.shields.io/discord/663420259851567114?color=blue&labelColor=292929&label=chat%20-%20discord&logo=discord&style=for-the-badge" /></a> <a href="https://discord.gg/X2TWhh9"><img alt="Discord" src="https://img.shields.io/discord/663420259851567114?color=blue&labelColor=292929&label=chat%20-%20discord&logo=discord&style=for-the-badge" /></a>
</p> </p>
## About ## About
@@ -19,10 +19,18 @@ Omega is a fork of Numworks' Epsilon, the OS that runs on their calculator, whic
- ~~32 KB Python heap instead of 16 KB~~ Now available on Epsilon `>=13.2.0`! - ~~32 KB Python heap instead of 16 KB~~ Now available on Epsilon `>=13.2.0`!
- And more... - And more...
The main new features are listed [here](https://github.com/Omega-Numworks/Omega/wiki/Main-features), and the complete changelog can be found [here](https://github.com/quentinguidee/Omega/wiki/Complete-changelog). The main new features are listed [here](https://github.com/Omega-Numworks/Omega/wiki/Main-features), and the complete changelog can be found [here](https://github.com/Omega-Numworks/Omega/wiki/Complete-changelog).
## Installation ## Installation
### Automatic
You can install Omega automatically on our website [here](https://getomega.web.app/) in the "install" page.
<a href="https://getomega.web.app"><p align="center"><img alt="Omega Banner Discord" src="https://user-images.githubusercontent.com/12123721/86352956-e9000480-bc66-11ea-82b7-79fd7e56fa27.png" /></p></a>
### Manual
First of all, follow **step 1** [here](https://www.numworks.com/resources/engineering/software/build/). Then: First of all, follow **step 1** [here](https://www.numworks.com/resources/engineering/software/build/). Then:
<details> <details>
@@ -110,6 +118,28 @@ Also, you can change the number of processes that run in parallel during the bui
</details> </details>
<details>
<summary><b>3DS Simulator</b></summary>
You need devkitPro and devkitARM installed and in your path (instructions [here](https://devkitpro.org/wiki/Getting_Started))
```
git clone --recursive https://github.com/Omega-Numworks/Omega.git
cd Omega
git checkout --recursive omega-dev
make PLATFORM=simulator TARGET=3ds -j
```
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:
```
3dslink output/release/simulator/3ds/epsilon.3dsx -a <3DS' IP ADDRESS>
```
</details>
If you need help, you can join our Discord server here : https://discord.gg/X2TWhh9
<a href="https://discord.gg/X2TWhh9"><p align="center"><img alt="Omega Banner Discord" src="https://user-images.githubusercontent.com/12123721/86287349-54ef5800-bbe8-11ea-80c1-34eb1f93eebd.png" /></p></a>
---
## Contributing ## Contributing
To contribute, please refer to the [Wiki](https://github.com/Omega-Numworks/Omega/wiki/Contributing) To contribute, please refer to the [Wiki](https://github.com/Omega-Numworks/Omega/wiki/Contributing)
@@ -126,9 +156,7 @@ To contribute, please refer to the [Wiki](https://github.com/Omega-Numworks/Omeg
* [Omega Website](https://github.com/Omega-Numworks/Omega-Website) * [Omega Website](https://github.com/Omega-Numworks/Omega-Website)
* [Omega RPN `APP`](https://github.com/Omega-Numworks/Omega-RPN) * [Omega RPN `APP`](https://github.com/Omega-Numworks/Omega-RPN)
* [Omega Atom `APP`](https://github.com/Omega-Numworks/Omega-Atom) * [Omega Atom `APP`](https://github.com/Omega-Numworks/Omega-Atom)
* [Omega Converter `APP`](https://github.com/Omega-Numworks/Omega-Converter)
* [Omega Design](https://github.com/Omega-Numworks/Omega-Design) * [Omega Design](https://github.com/Omega-Numworks/Omega-Design)
* [Omega CLI Installer `BETA`](https://github.com/Omega-Numworks/Omega-CLI-Installer)
* [Omega App Template `BETA`](https://github.com/Omega-Numworks/Omega-App-Template) * [Omega App Template `BETA`](https://github.com/Omega-Numworks/Omega-App-Template)
## About Epsilon ## About Epsilon
@@ -137,15 +165,11 @@ Omega is a fork of Epsilon, a high-performance graphing calculator operating sys
You can try Epsilon straight from your browser in the [online simulator](https://www.numworks.com/simulator/). You can try Epsilon straight from your browser in the [online simulator](https://www.numworks.com/simulator/).
## Contributors ✨
Thanks goes to these wonderful people!
<p align="center"><img src="https://github.com/Omega-Numworks/Omega-Design/blob/master/Omega-Contributors.png" /></p>
## License ## License
NumWorks is a registered trademark. Omega is not affiliated with NumWorks. 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.
* NumWorks Epsilon 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). * Omega is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode).

View File

@@ -1,3 +1,4 @@
include apps/helpers.mk
include apps/shared/Makefile include apps/shared/Makefile
include apps/home/Makefile include apps/home/Makefile
include apps/on_boarding/Makefile include apps/on_boarding/Makefile
@@ -10,8 +11,15 @@ apps =
# (path to the apps header). # (path to the apps header).
$(foreach i,${apps_list},${eval include apps/$(i)/Makefile}) $(foreach i,${apps_list},${eval include apps/$(i)/Makefile})
app_src += $(addprefix apps/,\ apps_src += $(addprefix apps/,\
alternate_empty_nested_menu_controller.cpp \
apps_container.cpp \ apps_container.cpp \
apps_container_launch_default.cpp:-onboarding \
apps_container_launch_on_boarding.cpp:+onboarding \
apps_container_prompt_beta.cpp:+beta \
apps_container_prompt_none.cpp:-beta \
apps_container_prompt_none.cpp:-update \
apps_container_prompt_update.cpp:+update \
apps_container_storage.cpp \ apps_container_storage.cpp \
apps_window.cpp \ apps_window.cpp \
backlight_dimming_timer.cpp \ backlight_dimming_timer.cpp \
@@ -19,27 +27,21 @@ app_src += $(addprefix apps/,\
battery_view.cpp \ battery_view.cpp \
empty_battery_window.cpp \ empty_battery_window.cpp \
exam_pop_up_controller.cpp \ exam_pop_up_controller.cpp \
exam_mode_configuration_official.cpp:+official \
exam_mode_configuration_non_official.cpp:-official \
global_preferences.cpp \ global_preferences.cpp \
i18n.py \ i18n.py \
lock_view.cpp \ lock_view.cpp \
main.cpp \ main.cpp \
math_toolbox.cpp \ math_toolbox.cpp \
math_variable_box_controller.cpp \
math_variable_box_empty_controller.cpp \
shift_alpha_lock_view.cpp \ shift_alpha_lock_view.cpp \
suspend_timer.cpp \ suspend_timer.cpp \
title_bar_view.cpp \ title_bar_view.cpp \
variable_box_controller.cpp \
variable_box_empty_controller.cpp \
) )
tests_src += apps/exam_mode_configuration_non_official.cpp tests_src += apps/exam_mode_configuration_non_official.cpp
apps_official += apps/exam_mode_configuration_non_official.cpp
apps_non_official += apps/exam_mode_configuration_non_official.cpp
apps_launch_on_boarding_src += apps/apps_container_launch_on_boarding.cpp
apps_launch_default_src += apps/apps_container_launch_default.cpp
apps_prompt_none_src += apps/apps_container_prompt_none.cpp
apps_prompt_beta_src += apps/apps_container_prompt_beta.cpp
apps_prompt_update_src += apps/apps_container_prompt_update.cpp
snapshots_declaration = $(foreach i,$(apps),$(i)::Snapshot m_snapshot$(subst :,,$(i))Snapshot;) snapshots_declaration = $(foreach i,$(apps),$(i)::Snapshot m_snapshot$(subst :,,$(i))Snapshot;)
apps_declaration = $(foreach i,$(apps),$(i) m_$(subst :,,$(i));) apps_declaration = $(foreach i,$(apps),$(i) m_$(subst :,,$(i));)
@@ -57,33 +59,20 @@ $(call object_for,apps/apps_container_storage.cpp apps/apps_container.cpp apps/m
SFLAGS += -I$(BUILD_DIR) SFLAGS += -I$(BUILD_DIR)
i18n_files += $(addprefix apps/language_,$(addsuffix .universal.i18n, $(EPSILON_I18N))) i18n_files += $(addprefix apps/language_,$(addsuffix .universal.i18n, $(EPSILON_I18N)))
i18n_files += $(addprefix apps/,\ ifeq ($(EPSILON_GETOPT),1)
shared.de.i18n\ i18n_files += $(addprefix apps/language_,$(addsuffix _iso6391.universal.i18n, $(EPSILON_I18N)))
shared.en.i18n\ endif
shared.es.i18n\
shared.fr.i18n\ i18n_files += $(call i18n_with_universal_for,shared)
shared.pt.i18n\ i18n_files += $(call i18n_without_universal_for,toolbox)
shared.hu.i18n\ i18n_files += $(call i18n_without_universal_for,variables)
shared.universal.i18n\
toolbox.de.i18n\
toolbox.en.i18n\
toolbox.es.i18n\
toolbox.fr.i18n\
toolbox.pt.i18n\
toolbox.hu.i18n\
variables.de.i18n\
variables.en.i18n\
variables.es.i18n\
variables.fr.i18n\
variables.pt.i18n\
variables.hu.i18n\
)
$(eval $(call rule_for, \ $(eval $(call rule_for, \
I18N, \ I18N, \
apps/i18n.cpp, \ apps/i18n.cpp, \
$(i18n_files), \ $(i18n_files), \
$$(PYTHON) apps/i18n.py --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --files $$^ \ $$(PYTHON) apps/i18n.py --codepoints $(code_points) --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --files $$^ --generateISO6391locales $$(EPSILON_GETOPT), \
global \
)) ))
@@ -94,36 +83,30 @@ $(BUILD_DIR)/apps/i18n.h: $(BUILD_DIR)/apps/i18n.cpp
$(eval $(call depends_on_image,apps/title_bar_view.cpp,apps/exam_icon.png)) $(eval $(call depends_on_image,apps/title_bar_view.cpp,apps/exam_icon.png))
all_app_src = $(app_src)(apps_launch_on_boarding_src) $(apps_launch_default_src) $(apps_prompt_none_src) $(apps_prompt_update_src) $(apps_prompt_beta_src) $(apps_official) $(apps_non_official) $(tests_src) $(call object_for,$(apps_src) $(tests_src)): $(BUILD_DIR)/apps/i18n.h
$(call object_for,$(apps_src) $(tests_src)): $(BUILD_DIR)/python/port/genhdr/qstrdefs.generated.h
$(call object_for,$(all_app_src)): $(BUILD_DIR)/apps/i18n.h apps_tests_src = $(app_calculation_test_src) $(app_code_test_src) $(app_probability_test_src) $(app_regression_test_src) $(app_sequence_test_src) $(app_shared_test_src) $(app_statistics_test_src) $(app_settings_test_src) $(app_solver_test_src)
$(call object_for,$(all_app_src)): $(BUILD_DIR)/python/port/genhdr/qstrdefs.generated.h
apps_tests_src = $(app_calculation_test_src) $(app_probability_test_src) $(app_regression_test_src) $(app_sequence_test_src) $(app_shared_test_src) $(app_statistics_test_src) $(app_settings_test_src) $(app_solver_test_src)
apps_tests_src += $(addprefix apps/,\ apps_tests_src += $(addprefix apps/,\
alternate_empty_nested_menu_controller.cpp \
global_preferences.cpp \ global_preferences.cpp \
) )
ifeq ($(THEME_REPO),local)
$(foreach img,$(image_list), $(eval $(call rule_for, \ $(foreach img,$(image_list), $(eval $(call rule_for, \
ICON, \ ICON, \
$(img), \ $(img), \
$(addprefix themes/themes/, $(addsuffix .json, $(OMEGA_THEME))), \ $(addprefix themes/themes/local/, $(addsuffix .json, $(THEME_NAME))), \
$$(PYTHON) themes/themes_manager.py -i $(OMEGA_THEME) $$@ $(BUILD_DIR)/ \ $$(PYTHON) themes/themes_manager.py -i $(THEME_REPO) $(THEME_NAME) $$@ $(BUILD_DIR)/, \
global \
))) )))
else
# Configure variants $(foreach img,$(image_list), $(eval $(call rule_for, \
apps_all_src = $(app_src) ICON, \
apps_all_src += $(apps_official) $(apps_non_official) $(img), \
apps_all_src += $(apps_launch_default_src) $(apps_launch_on_boarding_src) $(addsuffix /escher/palette.h, $(BUILD_DIR)), \
apps_all_src += $(apps_prompt_none_src) $(apps_prompt_update_src) $(apps_prompt_beta_src) $$(PYTHON) themes/themes_manager.py -i $(THEME_REPO) $(THEME_NAME) $$@ $(BUILD_DIR)/, \
global \
apps_default_src = $(app_src) $(apps_non_official) $(apps_launch_default_src) $(apps_prompt_none_src) )))
apps_official_default_src = $(app_src) $(apps_official) $(apps_launch_default_src) $(apps_prompt_none_src) endif
apps_onboarding_src = $(app_src) $(apps_non_official) $(apps_launch_on_boarding_src) $(apps_prompt_none_src)
apps_official_onboarding_src = $(app_src) $(apps_official) $(apps_launch_on_boarding_src) $(apps_prompt_none_src)
apps_onboarding_update_src = $(app_src) $(apps_non_official) $(apps_launch_on_boarding_src) $(apps_prompt_update_src)
apps_official_onboarding_update_src = $(app_src) $(apps_official) $(apps_launch_on_boarding_src) $(apps_prompt_update_src)
apps_onboarding_beta_src = $(app_src) $(apps_non_official) $(apps_launch_on_boarding_src) $(apps_prompt_beta_src)
apps_official_onboarding_beta_src = $(app_src) $(apps_official) $(apps_launch_on_boarding_src) $(apps_prompt_beta_src)

View File

@@ -0,0 +1,18 @@
#include "alternate_empty_nested_menu_controller.h"
void AlternateEmptyNestedMenuController::viewDidDisappear() {
if (isDisplayingEmptyController()) {
pop();
}
NestedMenuController::viewDidDisappear();
}
bool AlternateEmptyNestedMenuController::displayEmptyControllerIfNeeded() {
assert(!isDisplayingEmptyController());
// If the content is empty, we push an empty controller.
if (numberOfRows() == 0) {
push(emptyViewController());
return true;
}
return false;
}

View File

@@ -0,0 +1,19 @@
#ifndef APPS_ALTERNATE_EMPTY_NESTED_MENU_CONTROLLER_H
#define APPS_ALTERNATE_EMPTY_NESTED_MENU_CONTROLLER_H
#include <escher/nested_menu_controller.h>
class AlternateEmptyNestedMenuController : public NestedMenuController {
public:
AlternateEmptyNestedMenuController(I18n::Message title) :
NestedMenuController(nullptr, title)
{}
// View Controller
void viewDidDisappear() override;
protected:
virtual ViewController * emptyViewController() = 0;
bool isDisplayingEmptyController() { return StackViewController::depth() == 2; }
bool displayEmptyControllerIfNeeded();
};
#endif

View File

@@ -37,7 +37,7 @@ AppsContainer::AppsContainer() :
m_usbConnectedSnapshot() m_usbConnectedSnapshot()
{ {
m_emptyBatteryWindow.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), false); m_emptyBatteryWindow.setFrame(KDRect(0, 0, Ion::Display::Width, Ion::Display::Height), false);
#if __EMSCRIPTEN__ // #if __EMSCRIPTEN__
/* AppsContainer::poincareCircuitBreaker uses Ion::Keyboard::scan(), which /* AppsContainer::poincareCircuitBreaker uses Ion::Keyboard::scan(), which
* calls emscripten_sleep. If we set the poincare circuit breaker, we would * calls emscripten_sleep. If we set the poincare circuit breaker, we would
* need to whitelist all the methods that might be in the call stack when * need to whitelist all the methods that might be in the call stack when
@@ -47,9 +47,13 @@ AppsContainer::AppsContainer() :
* quite painy to maintain). * quite painy to maintain).
* We just remove the circuit breaker for now. * We just remove the circuit breaker for now.
* TODO: Put the Poincare circuit breaker back on epsilon's web emulator */ * TODO: Put the Poincare circuit breaker back on epsilon's web emulator */
#else
/*
* This can be run in Omega, since it uses WebASM.
*/
// #else
Poincare::Expression::SetCircuitBreaker(AppsContainer::poincareCircuitBreaker); Poincare::Expression::SetCircuitBreaker(AppsContainer::poincareCircuitBreaker);
#endif // #endif
Ion::Storage::sharedStorage()->setDelegate(this); Ion::Storage::sharedStorage()->setDelegate(this);
} }
@@ -88,7 +92,7 @@ MathToolbox * AppsContainer::mathToolbox() {
return &m_mathToolbox; return &m_mathToolbox;
} }
VariableBoxController * AppsContainer::variableBoxController() { MathVariableBoxController * AppsContainer::variableBoxController() {
return &m_variableBoxController; return &m_variableBoxController;
} }
@@ -218,6 +222,10 @@ bool AppsContainer::processEvent(Ion::Events::Event event) {
switchTo(appSnapshotAtIndex(0)); switchTo(appSnapshotAtIndex(0));
return true; return true;
} }
if (event == Ion::Events::ShiftHome) {
switchTo(appSnapshotAtIndex(1));
return true;
}
if (event == Ion::Events::OnOff) { if (event == Ion::Events::OnOff) {
suspend(true); suspend(true);
return true; return true;

View File

@@ -8,7 +8,7 @@
#include "apps_window.h" #include "apps_window.h"
#include "empty_battery_window.h" #include "empty_battery_window.h"
#include "math_toolbox.h" #include "math_toolbox.h"
#include "variable_box_controller.h" #include "math_variable_box_controller.h"
#include "exam_pop_up_controller.h" #include "exam_pop_up_controller.h"
#include "exam_pop_up_controller_delegate.h" #include "exam_pop_up_controller_delegate.h"
#include "battery_timer.h" #include "battery_timer.h"
@@ -34,9 +34,9 @@ public:
void reset(); void reset();
Poincare::Context * globalContext(); Poincare::Context * globalContext();
MathToolbox * mathToolbox(); MathToolbox * mathToolbox();
VariableBoxController * variableBoxController(); MathVariableBoxController * variableBoxController();
void suspend(bool checkIfOnOffKeyReleased = false); void suspend(bool checkIfOnOffKeyReleased = false);
virtual bool dispatchEvent(Ion::Events::Event event) override; bool dispatchEvent(Ion::Events::Event event) override;
bool switchTo(App::Snapshot * snapshot) override; bool switchTo(App::Snapshot * snapshot) override;
void run() override; void run() override;
bool updateBatteryState(); bool updateBatteryState();
@@ -70,7 +70,7 @@ private:
EmptyBatteryWindow m_emptyBatteryWindow; EmptyBatteryWindow m_emptyBatteryWindow;
Shared::GlobalContext m_globalContext; Shared::GlobalContext m_globalContext;
MathToolbox m_mathToolbox; MathToolbox m_mathToolbox;
VariableBoxController m_variableBoxController; MathVariableBoxController m_variableBoxController;
ExamPopUpController m_examPopUpController; ExamPopUpController m_examPopUpController;
OnBoarding::PopUpController m_promptController; OnBoarding::PopUpController m_promptController;
BatteryTimer m_batteryTimer; BatteryTimer m_batteryTimer;

View File

@@ -21,6 +21,7 @@ app_calculation_src = $(addprefix apps/calculation/,\
additional_outputs/trigonometry_graph_cell.cpp \ additional_outputs/trigonometry_graph_cell.cpp \
additional_outputs/trigonometry_list_controller.cpp \ additional_outputs/trigonometry_list_controller.cpp \
additional_outputs/trigonometry_model.cpp \ additional_outputs/trigonometry_model.cpp \
additional_outputs/unit_list_controller.cpp \
app.cpp \ app.cpp \
edit_expression_controller.cpp \ edit_expression_controller.cpp \
expression_field.cpp \ expression_field.cpp \
@@ -30,16 +31,9 @@ app_calculation_src = $(addprefix apps/calculation/,\
) )
app_calculation_src += $(app_calculation_test_src) app_calculation_src += $(app_calculation_test_src)
app_src += $(app_calculation_src) apps_src += $(app_calculation_src)
i18n_files += $(addprefix apps/calculation/,\ i18n_files += $(call i18n_without_universal_for,calculation/base)
base.de.i18n\
base.en.i18n\
base.es.i18n\
base.fr.i18n\
base.pt.i18n\
base.hu.i18n\
)
tests_src += $(addprefix apps/calculation/test/,\ tests_src += $(addprefix apps/calculation/test/,\
calculation_store.cpp\ calculation_store.cpp\

View File

@@ -1,4 +1,5 @@
#include "complex_graph_cell.h" #include "complex_graph_cell.h"
#include <escher/palette.h>
using namespace Shared; using namespace Shared;
using namespace Poincare; using namespace Poincare;
@@ -12,7 +13,7 @@ ComplexGraphView::ComplexGraphView(ComplexModel * complexModel) :
} }
void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const { void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(rect, KDColorWhite); ctx->fillRect(rect, Palette::BackgroundApps);
// Draw grid, axes and graduations // Draw grid, axes and graduations
drawGrid(ctx, rect); drawGrid(ctx, rect);
@@ -25,7 +26,7 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
assert(!std::isnan(real) && !std::isnan(imag) && !std::isinf(real) && !std::isinf(imag)); assert(!std::isnan(real) && !std::isnan(imag) && !std::isinf(real) && !std::isinf(imag));
// Draw the segment from the origin to the dot (real, imag) // Draw the segment from the origin to the dot (real, imag)
drawSegment(ctx, rect, 0.0f, 0.0f, m_complex->real(), m_complex->imag(), Palette::GreyDark, false); drawSegment(ctx, rect, 0.0f, 0.0f, m_complex->real(), m_complex->imag(), Palette::SecondaryText, false);
/* Draw the partial ellipse indicating the angle θ /* Draw the partial ellipse indicating the angle θ
* - the ellipse parameters are a = |real|/5 and b = |imag|/5, * - the ellipse parameters are a = |real|/5 and b = |imag|/5,
@@ -39,7 +40,7 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
* and the line of equation (real*t,imag*t). * and the line of equation (real*t,imag*t).
* (a*cos(t), b*sin(t)) = (real*t,imag*t) --> tan(t) = sign(a)*sign(b) (± π) * (a*cos(t), b*sin(t)) = (real*t,imag*t) --> tan(t) = sign(a)*sign(b) (± π)
* --> t = π/4 [π/2] according to sign(a) and sign(b). */ * --> t = π/4 [π/2] according to sign(a) and sign(b). */
float th = real < 0.0f ? 3.0f*M_PI/4.0f : M_PI/4.0f; float th = real < 0.0f ? (float)(3.0*M_PI_4) : (float)M_PI_4;
th = imag < 0.0f ? -th : th; th = imag < 0.0f ? -th : th;
// Compute ellipsis parameters a and b // Compute ellipsis parameters a and b
float factor = 5.0f; float factor = 5.0f;
@@ -48,7 +49,7 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
// Avoid flat ellipsis for edge cases (for real = 0, the case imag = 0 is excluded) // Avoid flat ellipsis for edge cases (for real = 0, the case imag = 0 is excluded)
if (real == 0.0f) { if (real == 0.0f) {
a = 1.0f/factor; a = 1.0f/factor;
th = imag < 0.0f ? -M_PI/2.0f : M_PI/2.0f; th = imag < 0.0f ? (float)-M_PI_2 : (float)M_PI_2;
} }
std::complex<float> parameters(a,b); std::complex<float> parameters(a,b);
drawCurve(ctx, rect, 0.0f, 1.0f, 0.01f, drawCurve(ctx, rect, 0.0f, 1.0f, 0.01f,
@@ -58,27 +59,27 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
float a = parameters.real(); float a = parameters.real();
float b = parameters.imag(); float b = parameters.imag();
return Poincare::Coordinate2D<float>(a*std::cos(t*th), b*std::sin(t*th)); return Poincare::Coordinate2D<float>(a*std::cos(t*th), b*std::sin(t*th));
}, &parameters, &th, false, Palette::GreyDark, false); }, &parameters, &th, false, Palette::SecondaryText, false);
// Draw dashed segment to indicate real and imaginary // Draw dashed segment to indicate real and imaginary
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3); drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::CalculationTrigoAndComplexForeground, 1, 3);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3); drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::CalculationTrigoAndComplexForeground, 1, 3);
// Draw complex position on the plan // Draw complex position on the plan
drawDot(ctx, rect, real, imag, Palette::Red, Size::Large); drawDot(ctx, rect, real, imag, Palette::CalculationTrigoAndComplexForeground, Size::Large);
// Draw labels // Draw labels
// 're(z)' label // 're(z)' label
drawLabel(ctx, rect, real, 0.0f, "re(z)", Palette::Red, CurveView::RelativePosition::None, imag >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After); drawLabel(ctx, rect, real, 0.0f, "re(z)", Palette::CalculationTrigoAndComplexForeground, CurveView::RelativePosition::None, imag >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After);
// 'im(z)' label // 'im(z)' label
drawLabel(ctx, rect, 0.0f, imag, "im(θ)", Palette::Red, real >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After, CurveView::RelativePosition::None); drawLabel(ctx, rect, 0.0f, imag, "im(z)", Palette::CalculationTrigoAndComplexForeground, real >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After, CurveView::RelativePosition::None);
// '|z|' label, the relative horizontal position of this label depends on the quadrant // '|z|' label, the relative horizontal position of this label depends on the quadrant
CurveView::RelativePosition verticalPosition = real*imag < 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After; CurveView::RelativePosition verticalPosition = real*imag < 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After;
if (real == 0.0f) { if (real == 0.0f) {
// Edge case: pure imaginary // Edge case: pure imaginary
verticalPosition = CurveView::RelativePosition::None; verticalPosition = CurveView::RelativePosition::None;
} }
drawLabel(ctx, rect, real/2.0f, imag/2.0f, "|z|", Palette::Red, CurveView::RelativePosition::None, verticalPosition); drawLabel(ctx, rect, real/2.0f, imag/2.0f, "|z|", Palette::CalculationTrigoAndComplexForeground, CurveView::RelativePosition::None, verticalPosition);
// 'arg(z)' label, the absolute and relative horizontal/vertical positions of this label depends on the quadrant // 'arg(z)' label, the absolute and relative horizontal/vertical positions of this label depends on the quadrant
CurveView::RelativePosition horizontalPosition = real >= 0.0f ? CurveView::RelativePosition::After : CurveView::RelativePosition::None; CurveView::RelativePosition horizontalPosition = real >= 0.0f ? CurveView::RelativePosition::After : CurveView::RelativePosition::None;
verticalPosition = imag >= 0.0f ? CurveView::RelativePosition::After : CurveView::RelativePosition::Before; verticalPosition = imag >= 0.0f ? CurveView::RelativePosition::After : CurveView::RelativePosition::Before;
@@ -87,7 +88,7 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
* and for the left half plan, we position the label at the half angle. The * and for the left half plan, we position the label at the half angle. The
* relative position is chosen accordingly. */ * relative position is chosen accordingly. */
float anglePositionRatio = real >= 0.0f ? 0.0f : 0.5f; float anglePositionRatio = real >= 0.0f ? 0.0f : 0.5f;
drawLabel(ctx, rect, a*std::cos(anglePositionRatio*th), b*std::sin(anglePositionRatio*th), "arg(z)", Palette::Red, horizontalPosition, verticalPosition); drawLabel(ctx, rect, a*std::cos(anglePositionRatio*th), b*std::sin(anglePositionRatio*th), "arg(z)", Palette::CalculationTrigoAndComplexForeground, horizontalPosition, verticalPosition);
} }
} }

View File

@@ -10,7 +10,7 @@ namespace Calculation {
class ComplexListController : public IllustratedListController { class ComplexListController : public IllustratedListController {
public: public:
ComplexListController(EditExpressionController * editExpressionController) : ComplexListController(EditExpressionController * editExpressionController) :
IllustratedListController(nullptr, editExpressionController), IllustratedListController(editExpressionController),
m_complexGraphCell(&m_model) {} m_complexGraphCell(&m_model) {}
// ViewController // ViewController

View File

@@ -17,10 +17,10 @@ float ComplexModel::rangeBound(float direction, bool horizontal) const {
maxFactor = k_maxHorizontalMarginFactor; maxFactor = k_maxHorizontalMarginFactor;
value = real(); value = real();
} }
if (std::isnan(value) || std::isinf(value) || value == 0.0f) {
return direction*maxFactor;
}
float factor = direction*value >= 0.0f ? maxFactor : minFactor; float factor = direction*value >= 0.0f ? maxFactor : minFactor;
if (std::isnan(value) || std::isinf(value) || value == 0.0f) {
return direction*factor;
}
return factor*value; return factor*value;
} }

View File

@@ -2,6 +2,7 @@
#define CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_MODEL_H #define CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_MODEL_H
#include "../../shared/curve_view_range.h" #include "../../shared/curve_view_range.h"
#include "illustrated_list_controller.h"
#include <complex> #include <complex>
namespace Calculation { namespace Calculation {
@@ -17,11 +18,53 @@ public:
void setComplex(std::complex<float> c) { *this = ComplexModel(c); } void setComplex(std::complex<float> c) { *this = ComplexModel(c); }
/* The range is computed from these criteria:
static constexpr float k_minVerticalMarginFactor = -0.5f; * - The real part is centered horizontally
static constexpr float k_maxVerticalMarginFactor = 1.2f; * - Both left and right margins are equal to the real length
* - The imaginary part is the same length as the real part
* - The remaining vertical margin are splitted as one third at the top, 2
* thirds at the bottom
*
* | | 1/3 * vertical_margin
* +----------+
* | / | |
* | / | | Imaginary
* | / | |
* | / | |
* ----------+----------+----------
* |
* | 2/3 * vertical_margin
* -----------
* Real
*
*/
// Horizontal range
static constexpr float k_minHorizontalMarginFactor = -1.0f; static constexpr float k_minHorizontalMarginFactor = -1.0f;
static constexpr float k_maxHorizontalMarginFactor = 2.0f; static constexpr float k_maxHorizontalMarginFactor = 2.0f;
// Vertical range
static constexpr KDCoordinate k_width = Ion::Display::Width - Metric::PopUpRightMargin - Metric::PopUpLeftMargin;
static constexpr KDCoordinate k_height = IllustratedListController::k_illustrationHeight;
static constexpr KDCoordinate k_unit = k_width/3;
/*
* VerticalMaring = k_height - k_unit
*
* Values | Coordinates
* --------+----------------------------------
* imag | k_unit
* Ymax | k_unit + (1/3)*VerticalMargin
* Ymin | -(2/3)*VerticalMargin
*
* Thus:
* Ymin = -(2/3)*k_verticalMargin*imag/k_unit
* = -(2/3)*(k_height/k_unit - 1)*imag
* = 2/3*(1 - k_height/k_unit)*imag
* Ymax = (k_unit + (1/3)*VerticalMargin)*imag/k_unit
* = (1 + (1/3)*(k_height/k_unit - 1))*imag
* = 1/3*(2 + k_height/k_unit)*imag
*
* */
static constexpr float k_minVerticalMarginFactor = 2.0f/3.0f*(1.0f - (float)k_height/(float)k_unit);
static constexpr float k_maxVerticalMarginFactor = 1.0f/3.0f*(2.0f + (float)k_height/(float)k_unit);
private: private:
float rangeBound(float direction, bool horizontal) const; float rangeBound(float direction, bool horizontal) const;

View File

@@ -4,13 +4,14 @@
#include <escher.h> #include <escher.h>
#include <apps/i18n.h> #include <apps/i18n.h>
#include <poincare/layout.h> #include <poincare/layout.h>
#include <escher/palette.h>
namespace Calculation { namespace Calculation {
class ExpressionWithEqualSignView : public ExpressionView { class ExpressionWithEqualSignView : public ExpressionView {
public: public:
ExpressionWithEqualSignView() : ExpressionWithEqualSignView() :
m_equalSign(KDFont::LargeFont, I18n::Message::Equal, 0.5f, 0.5f, KDColorBlack) m_equalSign(KDFont::LargeFont, I18n::Message::Equal, 0.5f, 0.5f, Palette::PrimaryText)
{} {}
KDSize minimalSizeForOptimalDisplay() const override; KDSize minimalSizeForOptimalDisplay() const override;
void drawRect(KDContext * ctx, KDRect rect) const override; void drawRect(KDContext * ctx, KDRect rect) const override;

View File

@@ -7,8 +7,8 @@ namespace Calculation {
/* Expressions list controller */ /* Expressions list controller */
ExpressionsListController::ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController) : ExpressionsListController::ExpressionsListController(EditExpressionController * editExpressionController) :
ListController(parentResponder, editExpressionController), ListController(editExpressionController),
m_cells{} m_cells{}
{ {
for (int i = 0; i < k_maxNumberOfCells; i++) { for (int i = 0; i < k_maxNumberOfCells; i++) {
@@ -38,9 +38,7 @@ HighlightCell * ExpressionsListController::reusableCell(int index, int type) {
KDCoordinate ExpressionsListController::rowHeight(int j) { KDCoordinate ExpressionsListController::rowHeight(int j) {
Layout l = layoutAtIndex(j); Layout l = layoutAtIndex(j);
if (l.isUninitialized()) { assert(!l.isUninitialized());
return 0;
}
return l.layoutSize().height() + 2 * Metric::CommonSmallMargin + Metric::CellSeparatorThickness; return l.layoutSize().height() + 2 * Metric::CommonSmallMargin + Metric::CellSeparatorThickness;
} }

View File

@@ -10,7 +10,7 @@ namespace Calculation {
class ExpressionsListController : public ListController { class ExpressionsListController : public ListController {
public: public:
ExpressionsListController(Responder * parentResponder, EditExpressionController * editExpressionController); ExpressionsListController(EditExpressionController * editExpressionController);
// Responder // Responder
void viewDidDisappear() override; void viewDidDisappear() override;
@@ -28,7 +28,7 @@ public:
protected: protected:
constexpr static int k_maxNumberOfCells = 4; constexpr static int k_maxNumberOfCells = 4;
virtual int textAtIndex(char * buffer, size_t bufferSize, int index) override; int textAtIndex(char * buffer, size_t bufferSize, int index) override;
Poincare::Expression m_expression; Poincare::Expression m_expression;
// Memoization of layouts // Memoization of layouts
mutable Poincare::Layout m_layouts[k_maxNumberOfCells]; mutable Poincare::Layout m_layouts[k_maxNumberOfCells];

View File

@@ -1,4 +1,5 @@
#include "illustrated_list_controller.h" #include "illustrated_list_controller.h"
#include <poincare/exception_checkpoint.h>
#include <poincare/symbol.h> #include <poincare/symbol.h>
#include "../app.h" #include "../app.h"
@@ -8,8 +9,8 @@ namespace Calculation {
/* Illustrated list controller */ /* Illustrated list controller */
IllustratedListController::IllustratedListController(Responder * parentResponder, EditExpressionController * editExpressionController) : IllustratedListController::IllustratedListController(EditExpressionController * editExpressionController) :
ListController(parentResponder, editExpressionController, this), ListController(editExpressionController, this),
m_additionalCalculationCells{} m_additionalCalculationCells{}
{ {
for (int i = 0; i < k_maxNumberOfAdditionalCalculations; i++) { for (int i = 0; i < k_maxNumberOfAdditionalCalculations; i++) {
@@ -78,7 +79,17 @@ KDCoordinate IllustratedListController::rowHeight(int j) {
return 0; return 0;
} }
Shared::ExpiringPointer<Calculation> calculation = m_calculationStore.calculationAtIndex(calculationIndex); Shared::ExpiringPointer<Calculation> calculation = m_calculationStore.calculationAtIndex(calculationIndex);
return calculation->height(App::app()->localContext(), true, true) + 2 * Metric::CommonSmallMargin + Metric::CellSeparatorThickness; constexpr bool expanded = true;
KDCoordinate result = calculation->memoizedHeight(expanded);
if (result < 0) {
result = ScrollableThreeExpressionsCell::Height(calculation.pointer());
if (result < 0) {
// Raise, because Height modified the calculation and failed.
Poincare::ExceptionCheckpoint::Raise();
}
calculation->setMemoizedHeight(expanded, result);
}
return result + Metric::CellSeparatorThickness;
} }
int IllustratedListController::typeAtLocation(int i, int j) { int IllustratedListController::typeAtLocation(int i, int j) {

View File

@@ -10,8 +10,10 @@
namespace Calculation { namespace Calculation {
class IllustratedListController : public ListController, public SelectableTableViewDelegate { class IllustratedListController : public ListController, public SelectableTableViewDelegate {
/* TODO There is factorizable code between this and
* Calculation::HistoryController (at least rowHeight). */
public: public:
IllustratedListController(Responder * parentResponder, EditExpressionController * editExpressionController); IllustratedListController(EditExpressionController * editExpressionController);
// Responder // Responder
void viewDidDisappear() override; void viewDidDisappear() override;
@@ -31,7 +33,7 @@ public:
// IllustratedListController // IllustratedListController
void setExpression(Poincare::Expression e) override; void setExpression(Poincare::Expression e) override;
constexpr static KDCoordinate k_illustrationHeight = 100; constexpr static KDCoordinate k_illustrationHeight = 120;
protected: protected:
Poincare::Expression m_savedExpression; Poincare::Expression m_savedExpression;
CalculationStore m_calculationStore; CalculationStore m_calculationStore;

View File

@@ -10,7 +10,7 @@ void IllustrationCell::layoutSubviews(bool force) {
} }
void IllustrationCell::drawRect(KDContext * ctx, KDRect rect) const { void IllustrationCell::drawRect(KDContext * ctx, KDRect rect) const {
drawBorderOfRect(ctx, bounds(), Palette::GreyBright); drawBorderOfRect(ctx, bounds(), Palette::ListCellBorder);
} }
} }

View File

@@ -28,9 +28,6 @@ Integer::Base baseAtIndex(int index) {
} }
void IntegerListController::computeLayoutAtIndex(int index) { void IntegerListController::computeLayoutAtIndex(int index) {
if (!m_layouts[index].isUninitialized()) {
return;
}
assert(m_expression.type() == ExpressionNode::Type::BasedInteger); assert(m_expression.type() == ExpressionNode::Type::BasedInteger);
// For index = k_indexOfFactorExpression, the layout is assumed to be alreday memoized because it is needed to compute the numberOfRows // For index = k_indexOfFactorExpression, the layout is assumed to be alreday memoized because it is needed to compute the numberOfRows
assert(index < k_indexOfFactorExpression); assert(index < k_indexOfFactorExpression);
@@ -65,6 +62,6 @@ bool IntegerListController::factorExpressionIsComputable() const {
} }
m_layouts[k_indexOfFactorExpression] = EmptyLayout::Builder(); m_layouts[k_indexOfFactorExpression] = EmptyLayout::Builder();
return false; return false;
}
} }
}

View File

@@ -8,7 +8,7 @@ namespace Calculation {
class IntegerListController : public ExpressionsListController { class IntegerListController : public ExpressionsListController {
public: public:
IntegerListController(EditExpressionController * editExpressionController) : IntegerListController(EditExpressionController * editExpressionController) :
ExpressionsListController(nullptr, editExpressionController) {} ExpressionsListController(editExpressionController) {}
//ListViewDataSource //ListViewDataSource
int numberOfRows() const override; int numberOfRows() const override;

View File

@@ -21,8 +21,8 @@ void ListController::InnerListController::didBecomeFirstResponder() {
/* List Controller */ /* List Controller */
ListController::ListController(Responder * parentResponder, EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate) : ListController::ListController(EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate) :
StackViewController(parentResponder, &m_listController, Palette::ToolboxHeaderText, Palette::ToolboxHeaderBackground, Palette::ToolboxHeaderBorder), StackViewController(nullptr, &m_listController, Palette::ToolboxHeaderText, Palette::ToolboxHeaderBackground, Palette::ToolboxHeaderBorder),
m_listController(this, delegate), m_listController(this, delegate),
m_editExpressionController(editExpressionController) m_editExpressionController(editExpressionController)
{ {
@@ -38,7 +38,6 @@ bool ListController::handleEvent(Ion::Events::Event event) {
* insertTextBody. */ * insertTextBody. */
Container::activeApp()->dismissModalViewController(); Container::activeApp()->dismissModalViewController();
m_editExpressionController->insertTextBody(buffer); m_editExpressionController->insertTextBody(buffer);
Container::activeApp()->setFirstResponder(m_editExpressionController);
return true; return true;
} }
return false; return false;

View File

@@ -10,7 +10,7 @@ class EditExpressionController;
class ListController : public StackViewController, public ListViewDataSource, public SelectableTableViewDataSource { class ListController : public StackViewController, public ListViewDataSource, public SelectableTableViewDataSource {
public: public:
ListController(Responder * parentResponder, EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate = nullptr); ListController(EditExpressionController * editExpressionController, SelectableTableViewDelegate * delegate = nullptr);
// Responder // Responder
bool handleEvent(Ion::Events::Event event) override; bool handleEvent(Ion::Events::Event event) override;

View File

@@ -8,7 +8,7 @@ namespace Calculation {
class RationalListController : public ExpressionsListController { class RationalListController : public ExpressionsListController {
public: public:
RationalListController(EditExpressionController * editExpressionController) : RationalListController(EditExpressionController * editExpressionController) :
ExpressionsListController(nullptr, editExpressionController) {} ExpressionsListController(editExpressionController) {}
//ListViewDataSource //ListViewDataSource
int numberOfRows() const override; int numberOfRows() const override;

View File

@@ -8,7 +8,8 @@ void ScrollableThreeExpressionsView::resetMemoization() {
setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout()); setLayouts(Poincare::Layout(), Poincare::Layout(), Poincare::Layout());
} }
void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) { void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation, bool * didForceOutput) {
assert(!didForceOutput || *didForceOutput == false);
Poincare::Context * context = App::app()->localContext(); Poincare::Context * context = App::app()->localContext();
// Clean the layouts to make room in the pool // Clean the layouts to make room in the pool
@@ -27,6 +28,9 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) {
Poincare::ExceptionCheckpoint::Raise(); Poincare::ExceptionCheckpoint::Raise();
} else { } else {
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
} }
} }
} }
@@ -46,6 +50,9 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) {
/* Set the display output to ApproximateOnly, make room in the pool by /* Set the display output to ApproximateOnly, make room in the pool by
* erasing the exact layout, and retry to create the approximate layout */ * erasing the exact layout, and retry to create the approximate layout */
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
exactOutputLayout = Poincare::Layout(); exactOutputLayout = Poincare::Layout();
couldNotCreateApproximateLayout = false; couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout); approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
@@ -65,6 +72,27 @@ void ScrollableThreeExpressionsView::setCalculation(Calculation * calculation) {
layoutSubviews(); layoutSubviews();
} }
KDCoordinate ScrollableThreeExpressionsCell::Height(Calculation * calculation) {
ScrollableThreeExpressionsCell cell;
bool didForceOutput = false;
cell.setCalculation(calculation, &didForceOutput);
if (didForceOutput) {
/* We could not compute the height of the calculation as it is (the display
* output was forced to another value during the height computation).
* Warning: the display output of calculation was actually changed, so it
* will cause problems if we already did some computations with another
* display value. */
return -1;
}
KDRect leftFrame = KDRectZero;
KDRect centerFrame = KDRectZero;
KDRect approximateSignFrame = KDRectZero;
KDRect rightFrame = KDRectZero;
cell.subviewFrames(&leftFrame, &centerFrame, &approximateSignFrame, &rightFrame);
KDRect unionedFrame = leftFrame.unionedWith(centerFrame).unionedWith(rightFrame);
return unionedFrame.height() + 2 * ScrollableThreeExpressionsView::k_margin;
}
void ScrollableThreeExpressionsCell::didBecomeFirstResponder() { void ScrollableThreeExpressionsCell::didBecomeFirstResponder() {
reinitSelection(); reinitSelection();
Container::activeApp()->setFirstResponder(&m_view); Container::activeApp()->setFirstResponder(&m_view);
@@ -75,8 +103,8 @@ void ScrollableThreeExpressionsCell::reinitSelection() {
m_view.reloadScroll(); m_view.reloadScroll();
} }
void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation) { void ScrollableThreeExpressionsCell::setCalculation(Calculation * calculation, bool * didForceOutput) {
m_view.setCalculation(calculation); m_view.setCalculation(calculation, didForceOutput);
layoutSubviews(); layoutSubviews();
} }

View File

@@ -5,22 +5,30 @@
#include "../../shared/scrollable_multiple_expressions_view.h" #include "../../shared/scrollable_multiple_expressions_view.h"
#include "../calculation.h" #include "../calculation.h"
#include "expression_with_equal_sign_view.h" #include "expression_with_equal_sign_view.h"
#include <escher/palette.h>
namespace Calculation { namespace Calculation {
/* TODO There is factorizable code between this and Calculation::HistoryViewCell
* (at least setCalculation). */
class ScrollableThreeExpressionsView : public Shared::AbstractScrollableMultipleExpressionsView { class ScrollableThreeExpressionsView : public Shared::AbstractScrollableMultipleExpressionsView {
public: public:
static constexpr KDCoordinate k_margin = Metric::CommonSmallMargin;
ScrollableThreeExpressionsView(Responder * parentResponder) : Shared::AbstractScrollableMultipleExpressionsView(parentResponder, &m_contentCell), m_contentCell() { ScrollableThreeExpressionsView(Responder * parentResponder) : Shared::AbstractScrollableMultipleExpressionsView(parentResponder, &m_contentCell), m_contentCell() {
setMargins(Metric::CommonSmallMargin, Metric::CommonSmallMargin, Metric::CommonSmallMargin, Metric::CommonSmallMargin); // Left Right margins are already added by TableCell setMargins(k_margin, k_margin, k_margin, k_margin); // Left Right margins are already added by TableCell
setBackgroundColor(KDColorWhite); setBackgroundColor(Palette::BackgroundApps);
} }
void resetMemoization(); void resetMemoization();
void setCalculation(Calculation * calculation); void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr);
void subviewFrames(KDRect * leftFrame, KDRect * centerFrame, KDRect * approximateSignFrame, KDRect * rightFrame) {
return m_contentCell.subviewFrames(leftFrame, centerFrame, approximateSignFrame, rightFrame);
}
private: private:
class ContentCell : public Shared::AbstractScrollableMultipleExpressionsView::ContentCell { class ContentCell : public Shared::AbstractScrollableMultipleExpressionsView::ContentCell {
public: public:
ContentCell() : m_leftExpressionView() {} ContentCell() : m_leftExpressionView() {}
KDColor backgroundColor() const override { return KDColorWhite; } KDColor backgroundColor() const override { return Palette::BackgroundApps; }
void setEven(bool even) override { return; } void setEven(bool even) override { return; }
ExpressionView * leftExpressionView() const override { return const_cast<ExpressionWithEqualSignView *>(&m_leftExpressionView); } ExpressionView * leftExpressionView() const override { return const_cast<ExpressionWithEqualSignView *>(&m_leftExpressionView); }
private: private:
@@ -28,12 +36,13 @@ private:
}; };
ContentCell * contentCell() override { return &m_contentCell; }; ContentCell * contentCell() override { return &m_contentCell; };
const ContentCell * constContentCell() const override { return &m_contentCell; }; const ContentCell * constContentCell() const override { return &m_contentCell; };
ContentCell m_contentCell; ContentCell m_contentCell;
}; };
class ScrollableThreeExpressionsCell : public TableCell, public Responder { class ScrollableThreeExpressionsCell : public TableCell, public Responder {
public: public:
static KDCoordinate Height(Calculation * calculation);
ScrollableThreeExpressionsCell() : ScrollableThreeExpressionsCell() :
Responder(nullptr), Responder(nullptr),
m_view(this) {} m_view(this) {}
@@ -52,12 +61,15 @@ public:
void setHighlighted(bool highlight) override { m_view.evenOddCell()->setHighlighted(highlight); } void setHighlighted(bool highlight) override { m_view.evenOddCell()->setHighlighted(highlight); }
void resetMemoization() { m_view.resetMemoization(); } void resetMemoization() { m_view.resetMemoization(); }
void setCalculation(Calculation * calculation); void setCalculation(Calculation * calculation, bool * didForceOutput = nullptr);
void setDisplayCenter(bool display); void setDisplayCenter(bool display);
ScrollableThreeExpressionsView::SubviewPosition selectedSubviewPosition() { return m_view.selectedSubviewPosition(); } ScrollableThreeExpressionsView::SubviewPosition selectedSubviewPosition() { return m_view.selectedSubviewPosition(); }
void setSelectedSubviewPosition(ScrollableThreeExpressionsView::SubviewPosition subviewPosition) { m_view.setSelectedSubviewPosition(subviewPosition); } void setSelectedSubviewPosition(ScrollableThreeExpressionsView::SubviewPosition subviewPosition) { m_view.setSelectedSubviewPosition(subviewPosition); }
void reinitSelection(); void reinitSelection();
void subviewFrames(KDRect * leftFrame, KDRect * centerFrame, KDRect * approximateSignFrame, KDRect * rightFrame) {
return m_view.subviewFrames(leftFrame, centerFrame, approximateSignFrame, rightFrame);
}
private: private:
// Remove label margin added by TableCell because they're already handled by ScrollableThreeExpressionsView // Remove label margin added by TableCell because they're already handled by ScrollableThreeExpressionsView
KDCoordinate labelMargin() const override { return 0; } KDCoordinate labelMargin() const override { return 0; }

View File

@@ -1,4 +1,5 @@
#include "trigonometry_graph_cell.h" #include "trigonometry_graph_cell.h"
#include <escher/palette.h>
using namespace Shared; using namespace Shared;
using namespace Poincare; using namespace Poincare;
@@ -14,24 +15,24 @@ TrigonometryGraphView::TrigonometryGraphView(TrigonometryModel * model) :
void TrigonometryGraphView::drawRect(KDContext * ctx, KDRect rect) const { void TrigonometryGraphView::drawRect(KDContext * ctx, KDRect rect) const {
float s = std::sin(m_model->angle()); float s = std::sin(m_model->angle());
float c = std::cos(m_model->angle()); float c = std::cos(m_model->angle());
ctx->fillRect(rect, KDColorWhite); ctx->fillRect(rect, Palette::BackgroundApps);
drawGrid(ctx, rect); drawGrid(ctx, rect);
drawAxes(ctx, rect); drawAxes(ctx, rect);
// Draw the circle // Draw the circle
drawCurve(ctx, rect, 0.0f, 2.0f*M_PI, M_PI/180.0f, [](float t, void * model, void * context) { drawCurve(ctx, rect, 0.0f, 2.0f*M_PI, M_PI/180.0f, [](float t, void * model, void * context) {
return Poincare::Coordinate2D<float>(std::cos(t), std::sin(t)); return Poincare::Coordinate2D<float>(std::cos(t), std::sin(t));
}, nullptr, nullptr, true, Palette::GreyDark, false); }, nullptr, nullptr, true, Palette::SecondaryText, false);
// Draw dashed segment to indicate sine and cosine // Draw dashed segment to indicate sine and cosine
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::Red, 1, 3); drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::CalculationTrigoAndComplexForeground, 1, 3);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::Red, 1, 3); drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::CalculationTrigoAndComplexForeground, 1, 3);
// Draw angle position on the circle // Draw angle position on the circle
drawDot(ctx, rect, c, s, Palette::Red, Size::Large); drawDot(ctx, rect, c, s, Palette::CalculationTrigoAndComplexForeground, Size::Large);
// Draw graduations // Draw graduations
drawLabelsAndGraduations(ctx, rect, Axis::Vertical, false, true); drawLabelsAndGraduations(ctx, rect, Axis::Vertical, false, true);
drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, false, true); drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, false, true);
// Draw labels // Draw labels
drawLabel(ctx, rect, 0.0f, s, "sin(θ)", Palette::Red, c >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After, CurveView::RelativePosition::None); drawLabel(ctx, rect, 0.0f, s, "sin(θ)", Palette::CalculationTrigoAndComplexForeground, c >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After, CurveView::RelativePosition::None);
drawLabel(ctx, rect, c, 0.0f, "cos(θ)", Palette::Red, CurveView::RelativePosition::None, s >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After); drawLabel(ctx, rect, c, 0.0f, "cos(θ)", Palette::CalculationTrigoAndComplexForeground, CurveView::RelativePosition::None, s >= 0.0f ? CurveView::RelativePosition::Before : CurveView::RelativePosition::After);
} }
} }

View File

@@ -10,7 +10,7 @@ namespace Calculation {
class TrigonometryListController : public IllustratedListController { class TrigonometryListController : public IllustratedListController {
public: public:
TrigonometryListController(EditExpressionController * editExpressionController) : TrigonometryListController(EditExpressionController * editExpressionController) :
IllustratedListController(nullptr, editExpressionController), IllustratedListController(editExpressionController),
m_graphCell(&m_model) {} m_graphCell(&m_model) {}
void setExpression(Poincare::Expression e) override; void setExpression(Poincare::Expression e) override;
private: private:

View File

@@ -18,7 +18,7 @@ public:
float yMax() const override { return yCenter() + yHalfRange(); } float yMax() const override { return yCenter() + yHalfRange(); }
void setAngle(float f) { m_angle = f; } void setAngle(float f) { m_angle = f; }
float angle() const { return m_angle*M_PI/Poincare::Trigonometry::PiInAngleUnit(Poincare::Preferences::sharedPreferences()->angleUnit()); } float angle() const { return m_angle*(float)M_PI/(float)Poincare::Trigonometry::PiInAngleUnit(Poincare::Preferences::sharedPreferences()->angleUnit()); }
private: private:
constexpr static float k_xHalfRange = 2.1f; constexpr static float k_xHalfRange = 2.1f;
// We center the yRange around the semi-circle where the angle is // We center the yRange around the semi-circle where the angle is

View File

@@ -0,0 +1,155 @@
#include "unit_list_controller.h"
#include "../app.h"
#include "../../shared/poincare_helpers.h"
#include <poincare/unit_convert.h>
#include <poincare/multiplication.h>
#include <poincare/power.h>
#include <poincare/undefined.h>
#include <poincare/unit.h>
using namespace Poincare;
using namespace Shared;
namespace Calculation {
void UnitListController::setExpression(Poincare::Expression e) {
ExpressionsListController::setExpression(e);
assert(!m_expression.isUninitialized());
// Reinitialize m_memoizedExpressions
for (size_t i = 0; i < k_maxNumberOfCells; i++) {
m_memoizedExpressions[i] = Expression();
}
size_t numberOfMemoizedExpressions = 0;
// 1. First rows: miscellaneous classic units for some dimensions
Expression copy = m_expression.clone();
Expression units;
// Reduce to be able to recognize units
PoincareHelpers::Reduce(&copy, App::app()->localContext(), ExpressionNode::ReductionTarget::User);
copy = copy.removeUnit(&units);
bool requireSimplification = false;
bool canChangeUnitPrefix = false;
if (Unit::IsSISpeed(units)) {
// 1.a. Turn speed into km/h
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
m_expression.clone(),
Multiplication::Builder(
Unit::Kilometer(),
Power::Builder(
Unit::Hour(),
Rational::Builder(-1)
)
)
);
requireSimplification = true; // Simplify the conversion
} else if (Unit::IsSIVolume(units)) {
// 1.b. Turn volume into L
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
m_expression.clone(),
Unit::Liter()
);
requireSimplification = true; // Simplify the conversion
canChangeUnitPrefix = true; // Pick best prefix (mL)
} else if (Unit::IsSIEnergy(units)) {
// 1.c. Turn energy into Wh
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
m_expression.clone(),
Multiplication::Builder(
Unit::Watt(),
Unit::Hour()
)
);
m_memoizedExpressions[numberOfMemoizedExpressions++] = UnitConvert::Builder(
m_expression.clone(),
Unit::ElectronVolt()
);
requireSimplification = true; // Simplify the conversion
canChangeUnitPrefix = true; // Pick best prefix (kWh)
} else if (Unit::IsSITime(units)) {
// Turn time into ? year + ? month + ? day + ? h + ? min + ? s
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(copy, App::app()->localContext());
m_memoizedExpressions[numberOfMemoizedExpressions++] = Unit::BuildTimeSplit(value, App::app()->localContext(), Preferences::sharedPreferences()->complexFormat(), Preferences::sharedPreferences()->angleUnit());
}
// 1.d. Simplify and tune prefix of all computed expressions
size_t currentExpressionIndex = 0;
while (currentExpressionIndex < numberOfMemoizedExpressions) {
assert(!m_memoizedExpressions[currentExpressionIndex].isUninitialized());
if (requireSimplification) {
Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User);
}
if (canChangeUnitPrefix) {
Expression newUnits;
// Reduce to be able to removeUnit
PoincareHelpers::Reduce(&m_memoizedExpressions[currentExpressionIndex], App::app()->localContext(), ExpressionNode::ReductionTarget::User);
m_memoizedExpressions[currentExpressionIndex] = m_memoizedExpressions[currentExpressionIndex].removeUnit(&newUnits);
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(m_memoizedExpressions[currentExpressionIndex], App::app()->localContext());
ExpressionNode::ReductionContext reductionContext(
App::app()->localContext(),
Preferences::sharedPreferences()->complexFormat(),
Preferences::sharedPreferences()->angleUnit(),
ExpressionNode::ReductionTarget::User,
ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined);
Unit::ChooseBestPrefixForValue(&newUnits, &value, reductionContext);
m_memoizedExpressions[currentExpressionIndex] = Multiplication::Builder(Number::FloatNumber(value), newUnits);
}
currentExpressionIndex++;
}
// 2. IS units only
assert(numberOfMemoizedExpressions < k_maxNumberOfCells - 1);
m_memoizedExpressions[numberOfMemoizedExpressions] = m_expression.clone();
Shared::PoincareHelpers::Simplify(&m_memoizedExpressions[numberOfMemoizedExpressions], App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::InternationalSystem);
numberOfMemoizedExpressions++;
// 3. Get rid of duplicates
Expression reduceExpression = m_expression.clone();
// Make m_expression compareable to m_memoizedExpressions (turn BasedInteger into Rational for instance)
Shared::PoincareHelpers::Simplify(&reduceExpression, App::app()->localContext(), ExpressionNode::ReductionTarget::User, Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, Poincare::ExpressionNode::UnitConversion::None);
currentExpressionIndex = 1;
while (currentExpressionIndex < numberOfMemoizedExpressions) {
bool duplicateFound = false;
for (size_t i = 0; i < currentExpressionIndex + 1; i++) {
// Compare the currentExpression to all previous memoized expressions and to m_expression
Expression comparedExpression = i == currentExpressionIndex ? reduceExpression : m_memoizedExpressions[i];
assert(!comparedExpression.isUninitialized());
if (comparedExpression.isIdenticalTo(m_memoizedExpressions[currentExpressionIndex])) {
numberOfMemoizedExpressions--;
// Shift next expressions
for (size_t j = currentExpressionIndex; j < numberOfMemoizedExpressions; j++) {
m_memoizedExpressions[j] = m_memoizedExpressions[j+1];
}
// Remove last expression
m_memoizedExpressions[numberOfMemoizedExpressions] = Expression();
// The current expression has been discarded, no need to increment the current index
duplicateFound = true;
break;
}
}
if (!duplicateFound) {
// The current expression is not a duplicate, check next expression
currentExpressionIndex++;
}
}
}
int UnitListController::numberOfRows() const {
int nbOfRows = 0;
for (size_t i = 0; i < k_maxNumberOfCells; i++) {
if (!m_memoizedExpressions[i].isUninitialized()) {
nbOfRows++;
}
}
return nbOfRows;
}
void UnitListController::computeLayoutAtIndex(int index) {
assert(!m_memoizedExpressions[index].isUninitialized());
m_layouts[index] = Shared::PoincareHelpers::CreateLayout(m_memoizedExpressions[index]);
}
I18n::Message UnitListController::messageAtIndex(int index) {
return (I18n::Message)0;
}
}

View File

@@ -0,0 +1,26 @@
#ifndef CALCULATION_ADDITIONAL_OUTPUTS_UNIT_LIST_CONTROLLER_H
#define CALCULATION_ADDITIONAL_OUTPUTS_UNIT_LIST_CONTROLLER_H
#include "expressions_list_controller.h"
namespace Calculation {
class UnitListController : public ExpressionsListController {
public:
UnitListController(EditExpressionController * editExpressionController) :
ExpressionsListController(editExpressionController) {}
void setExpression(Poincare::Expression e) override;
//ListViewDataSource
int numberOfRows() const override;
private:
void computeLayoutAtIndex(int index) override;
I18n::Message messageAtIndex(int index) override;
// Memoization of expressions
mutable Poincare::Expression m_memoizedExpressions[k_maxNumberOfCells];
};
}
#endif

View File

@@ -17,8 +17,8 @@ I18n::Message App::Descriptor::upperName() {
return I18n::Message::CalculAppCapital; return I18n::Message::CalculAppCapital;
} }
int App::Descriptor::examinationLevel() { App::Descriptor::ExaminationLevel App::Descriptor::examinationLevel() {
return App::Descriptor::StrictExaminationLevel; return App::Descriptor::ExaminationLevel::Strict;
} }
const Image * App::Descriptor::icon() { const Image * App::Descriptor::icon() {

View File

@@ -15,7 +15,7 @@ public:
public: public:
I18n::Message name() override; I18n::Message name() override;
I18n::Message upperName() override; I18n::Message upperName() override;
int examinationLevel() override; App::Descriptor::ExaminationLevel examinationLevel() override;
const Image * icon() override; const Image * icon() override;
}; };
class Snapshot : public ::App::Snapshot { class Snapshot : public ::App::Snapshot {

View File

@@ -4,6 +4,6 @@ AdditionalResults = "Weitere Ergebnisse"
DecimalBase = "Dezimal" DecimalBase = "Dezimal"
HexadecimalBase = "Hexadezimal" HexadecimalBase = "Hexadezimal"
BinaryBase = "Binär" BinaryBase = "Binär"
PrimeFactors = "Primfaktor" PrimeFactors = "Primfaktoren"
MixedFraction = "Gemischte Fraktion" MixedFraction = "Gemischte Zahl"
EuclideanDivision = "Euklidische Division" EuclideanDivision = "Division mit Rest"

View File

@@ -1,9 +1,9 @@
CalculApp = "Cálculo" CalculApp = "Cálculo"
CalculAppCapital = "CÁLCULO" CalculAppCapital = "CÁLCULO"
AdditionalResults = "????" AdditionalResults = "Resultados adicionales"
DecimalBase = "????" DecimalBase = "Decimal"
HexadecimalBase = "????" HexadecimalBase = "Hexadecimal"
BinaryBase = "????" BinaryBase = "Binario"
PrimeFactors = "????" PrimeFactors = "Factores primos"
MixedFraction = "????" MixedFraction = "Fracción mixta"
EuclideanDivision = "????" EuclideanDivision = "División euclidiana"

View File

@@ -0,0 +1,9 @@
CalculApp = "Calcolo"
CalculAppCapital = "CALCOLO"
AdditionalResults = "Risultati complementari"
DecimalBase = "Decimale"
HexadecimalBase = "Esadecimale"
BinaryBase = "Binario"
PrimeFactors = "Fattori primi"
MixedFraction = "Frazione mista"
EuclideanDivision = "Divisione euclidea"

View File

@@ -0,0 +1,9 @@
CalculApp = "Calculatie"
CalculAppCapital = "CALCULATIE"
AdditionalResults = "Bijkomende resultaten"
DecimalBase = "Decimaal"
HexadecimalBase = "Hexadecimaal"
BinaryBase = "Binaire"
PrimeFactors = "Priemfactoren"
MixedFraction = "Gemengde breuk"
EuclideanDivision = "Geheeltallige deling"

View File

@@ -1,9 +1,9 @@
CalculApp = "Cálculo" CalculApp = "Cálculo"
CalculAppCapital = "CÁLCULO" CalculAppCapital = "CÁLCULO"
AdditionalResults = "????" AdditionalResults = "Resultados adicionais"
DecimalBase = "????" DecimalBase = "Decimal"
HexadecimalBase = "????" HexadecimalBase = "Hexadecimal"
BinaryBase = "????" BinaryBase = "Binário"
PrimeFactors = "????" PrimeFactors = "Fatores primos"
MixedFraction = "????" MixedFraction = "Fração mista"
EuclideanDivision = "????" EuclideanDivision = "Divisão euclidiana"

View File

@@ -1,20 +1,22 @@
#include "calculation.h" #include "calculation.h"
#include "../shared/poincare_helpers.h" #include "../shared/poincare_helpers.h"
#include "../shared/scrollable_multiple_expressions_view.h"
#include "../global_preferences.h" #include "../global_preferences.h"
#include "../exam_mode_configuration.h" #include "../exam_mode_configuration.h"
#include "app.h"
#include <poincare/exception_checkpoint.h> #include <poincare/exception_checkpoint.h>
#include <poincare/undefined.h> #include <poincare/undefined.h>
#include <poincare/unit.h>
#include <poincare/unreal.h> #include <poincare/unreal.h>
#include <string.h> #include <string.h>
#include <cmath> #include <cmath>
#include <algorithm>
using namespace Poincare; using namespace Poincare;
using namespace Shared; using namespace Shared;
namespace Calculation { namespace Calculation {
static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
bool Calculation::operator==(const Calculation& c) { bool Calculation::operator==(const Calculation& c) {
return strcmp(inputText(), c.inputText()) == 0 return strcmp(inputText(), c.inputText()) == 0
&& strcmp(approximateOutputText(NumberOfSignificantDigits::Maximal), c.approximateOutputText(NumberOfSignificantDigits::Maximal)) == 0 && strcmp(approximateOutputText(NumberOfSignificantDigits::Maximal), c.approximateOutputText(NumberOfSignificantDigits::Maximal)) == 0
@@ -39,8 +41,7 @@ Calculation * Calculation::next() const {
void Calculation::tidy() { void Calculation::tidy() {
/* Reset height memoization (the complex format could have changed when /* Reset height memoization (the complex format could have changed when
* re-entering Calculation app which would impact the heights). */ * re-entering Calculation app which would impact the heights). */
m_height = -1; resetHeightMemoization();
m_expandedHeight = -1;
} }
const char * Calculation::approximateOutputText(NumberOfSignificantDigits numberOfSignificantDigits) const { const char * Calculation::approximateOutputText(NumberOfSignificantDigits numberOfSignificantDigits) const {
@@ -125,123 +126,12 @@ Layout Calculation::createApproximateOutputLayout(Context * context, bool * coul
} }
} }
KDCoordinate Calculation::height(Context * context, bool expanded, bool allExpressionsInline) { void Calculation::setMemoizedHeight(bool expanded, KDCoordinate height) {
KDCoordinate result = expanded ? m_expandedHeight : m_height; if (expanded) {
if (result >= 0) { m_expandedHeight = height;
// Height already computed
return result;
}
// Get input height
Layout inputLayout = createInputLayout();
KDCoordinate inputHeight = inputLayout.layoutSize().height();
KDCoordinate inputWidth = inputLayout.layoutSize().width();
float singleMargin = 2 * Metric::CommonSmallMargin;
float doubleMargin = 4 * Metric::CommonSmallMargin;
bool singleLine = false;
KDCoordinate inputBaseline = inputLayout.baseline();
// Get exact output height if needed
Poincare::Layout exactLayout;
bool couldNotCreateExactLayout = false;
if (DisplaysExact(displayOutput(context))) {
// Create the exact output layout
exactLayout = createExactOutputLayout(&couldNotCreateExactLayout);
if (couldNotCreateExactLayout) {
if (displayOutput(context) != DisplayOutput::ExactOnly) {
forceDisplayOutput(DisplayOutput::ApproximateOnly);
} else {
/* We should only display the exact result, but we cannot create it
* -> raise an exception. */
ExceptionCheckpoint::Raise();
}
}
}
if (displayOutput(context) == DisplayOutput::ExactOnly) {
KDCoordinate exactOutputHeight = exactLayout.layoutSize().height();
KDCoordinate exactOutputWidth = exactLayout.layoutSize().width();
singleLine = exactOutputWidth + inputWidth < maxWidth - 40;
if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact && !allExpressionsInline) {
KDCoordinate exactOutputBaseline = exactLayout.baseline();
result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline) + singleMargin;
} else {
if (allExpressionsInline) {
KDCoordinate exactOutputBaseline = exactLayout.baseline();
result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline);
} else {
result = inputHeight + exactOutputHeight + doubleMargin;
}
}
} else { } else {
bool couldNotCreateApproximateLayout = false; m_height = height;
Layout approximateLayout = createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
if (couldNotCreateApproximateLayout) {
if (displayOutput(context) == DisplayOutput::ApproximateOnly) {
Poincare::ExceptionCheckpoint::Raise();
} else {
/* Set the display output to ApproximateOnly, make room in the pool by
* erasing the exact layout, and retry to create the approximate layout */
forceDisplayOutput(DisplayOutput::ApproximateOnly);
exactLayout = Poincare::Layout();
couldNotCreateApproximateLayout = false;
approximateLayout = createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
if (couldNotCreateApproximateLayout) {
Poincare::ExceptionCheckpoint::Raise();
}
}
}
KDCoordinate approximateOutputHeight = approximateLayout.layoutSize().height();
KDCoordinate approximateOutputWidth = approximateLayout.layoutSize().width();
singleLine = approximateOutputWidth + inputWidth < maxWidth - 40;
if (displayOutput(context) == DisplayOutput::ApproximateOnly || (!expanded && displayOutput(context) == DisplayOutput::ExactAndApproximateToggle)) {
if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact && !allExpressionsInline) {
KDCoordinate approximateOutputBaseline = approximateLayout.baseline();
result = maxCoordinate(inputBaseline, approximateOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, approximateOutputHeight-approximateOutputBaseline) + singleMargin;
} else {
if (allExpressionsInline) {
KDCoordinate approximateOutputBaseline = approximateLayout.baseline();
result = maxCoordinate(inputBaseline, approximateOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, approximateOutputHeight-approximateOutputBaseline);
} else {
result = inputHeight + approximateOutputHeight + doubleMargin;
}
}
} else {
assert(displayOutput(context) == DisplayOutput::ExactAndApproximate || (displayOutput(context) == DisplayOutput::ExactAndApproximateToggle && expanded));
KDCoordinate exactOutputHeight = exactLayout.layoutSize().height();
KDCoordinate exactOutputBaseline = exactLayout.baseline();
KDCoordinate exactOutputWidth = exactLayout.layoutSize().width();
KDCoordinate approximateOutputWidth = approximateLayout.layoutSize().width();
singleLine = exactOutputWidth + approximateOutputWidth + inputWidth < maxWidth - 70;
KDCoordinate approximateOutputBaseline = approximateLayout.baseline();
if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact) {
result = maxCoordinate(inputBaseline, maxCoordinate(exactOutputBaseline, approximateOutputBaseline)) + maxCoordinate(inputHeight - inputBaseline, maxCoordinate(exactOutputHeight - exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline)) + singleMargin;
} else {
if (allExpressionsInline) {
result = maxCoordinate(inputBaseline, maxCoordinate(exactOutputBaseline, approximateOutputBaseline)) + maxCoordinate(inputHeight - inputBaseline, maxCoordinate(exactOutputHeight - exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline));
} else {
KDCoordinate outputHeight = maxCoordinate(exactOutputBaseline, approximateOutputBaseline) + maxCoordinate(exactOutputHeight-exactOutputBaseline, approximateOutputHeight-approximateOutputBaseline);
result = inputHeight + outputHeight + doubleMargin;
}
}
}
} }
/* For all display outputs except ExactAndApproximateToggle, the selected
* height and the usual height are identical. We update both heights in
* theses cases. */
if (displayOutput(context) != DisplayOutput::ExactAndApproximateToggle) {
m_height = result;
m_expandedHeight = result;
} else {
if (expanded) {
m_expandedHeight = result;
} else {
m_height = result;
}
}
return result;
} }
Calculation::DisplayOutput Calculation::displayOutput(Context * context) { Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
@@ -285,7 +175,7 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
ExpressionNode::Type::PredictionInterval ExpressionNode::Type::PredictionInterval
}; };
return e.isOfType(approximateOnlyTypes, sizeof(approximateOnlyTypes)/sizeof(ExpressionNode::Type)); return e.isOfType(approximateOnlyTypes, sizeof(approximateOnlyTypes)/sizeof(ExpressionNode::Type));
}, context, true) }, context)
) )
{ {
m_displayOutput = DisplayOutput::ApproximateOnly; m_displayOutput = DisplayOutput::ApproximateOnly;
@@ -302,15 +192,15 @@ Calculation::DisplayOutput Calculation::displayOutput(Context * context) {
void Calculation::forceDisplayOutput(DisplayOutput d) { void Calculation::forceDisplayOutput(DisplayOutput d) {
m_displayOutput = d; m_displayOutput = d;
// Reset heights memoization as it might have changed when we modify the display output // Reset heights memoization as it might have changed when we modify the display output
m_height = -1; resetHeightMemoization();
m_expandedHeight = -1;
} }
bool Calculation::shouldOnlyDisplayExactOutput() { bool Calculation::shouldOnlyDisplayExactOutput() {
/* If the input is a "store in a function", do not display the approximate /* If the input is a "store in a function", do not display the approximate
* result. This prevents x->f(x) from displaying x = undef. */ * result. This prevents x->f(x) from displaying x = undef. */
Expression i = input(); Expression i = input();
return i.type() == ExpressionNode::Type::Store return (i.type() == ExpressionNode::Type::Store && i.childAtIndex(1).type() == ExpressionNode::Type::Function)
&& i.childAtIndex(1).type() == ExpressionNode::Type::Function; || strcmp(approximateOutputText(NumberOfSignificantDigits::Maximal), Undefined::Name()) == 0;
} }
Calculation::EqualSign Calculation::exactAndApproximateDisplayedOutputsAreEqual(Poincare::Context * context) { Calculation::EqualSign Calculation::exactAndApproximateDisplayedOutputsAreEqual(Poincare::Context * context) {
@@ -340,6 +230,9 @@ Calculation::EqualSign Calculation::exactAndApproximateDisplayedOutputsAreEqual(
} }
Calculation::AdditionalInformationType Calculation::additionalInformationType(Context * context) { Calculation::AdditionalInformationType Calculation::additionalInformationType(Context * context) {
if (ExamModeConfiguration::exactExpressionsAreForbidden(GlobalPreferences::sharedGlobalPreferences()->examMode())) {
return AdditionalInformationType::None;
}
Preferences * preferences = Preferences::sharedPreferences(); Preferences * preferences = Preferences::sharedPreferences();
Preferences::ComplexFormat complexFormat = Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), m_inputText); Preferences::ComplexFormat complexFormat = Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), m_inputText);
Expression i = input(); Expression i = input();
@@ -361,8 +254,28 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
if (input().isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit()) || o.isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit())) { if (input().isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit()) || o.isDefinedCosineOrSine(context, complexFormat, preferences->angleUnit())) {
return AdditionalInformationType::Trigonometry; return AdditionalInformationType::Trigonometry;
} }
if (o.hasUnit()) {
// TODO: return AdditionalInformationType::Unit Expression unit;
PoincareHelpers::Reduce(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User,ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None);
o = o.removeUnit(&unit);
if (Unit::IsSI(unit)) {
if (Unit::IsSISpeed(unit) || Unit::IsSIVolume(unit) || Unit::IsSIEnergy(unit)) {
/* All these units will provide misc. classic representatives in
* addition to the SI unit in additional information. */
return AdditionalInformationType::Unit;
}
if (Unit::IsSITime(unit)) {
/* If the number of seconds is above 60s, we can write it in the form
* of an addition: 23_min + 12_s for instance. */
double value = Shared::PoincareHelpers::ApproximateToScalar<double>(o, App::app()->localContext());
if (value > Unit::SecondsPerMinute) {
return AdditionalInformationType::Unit;
}
}
return AdditionalInformationType::None;
}
return AdditionalInformationType::Unit;
}
if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) { if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) {
return AdditionalInformationType::Integer; return AdditionalInformationType::Integer;
} }
@@ -376,4 +289,9 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co
return AdditionalInformationType::None; return AdditionalInformationType::None;
} }
void Calculation::resetHeightMemoization() {
m_height = -1;
m_expandedHeight = -1;
}
} }

View File

@@ -84,7 +84,8 @@ public:
Poincare::Layout createApproximateOutputLayout(Poincare::Context * context, bool * couldNotCreateApproximateLayout); Poincare::Layout createApproximateOutputLayout(Poincare::Context * context, bool * couldNotCreateApproximateLayout);
// Memoization of height // Memoization of height
KDCoordinate height(Poincare::Context * context, bool expanded = false, bool allExpressionsInline = false); KDCoordinate memoizedHeight(bool expanded) { return expanded ? m_expandedHeight : m_height; }
void setMemoizedHeight(bool expanded, KDCoordinate height);
// Displayed output // Displayed output
DisplayOutput displayOutput(Poincare::Context * context); DisplayOutput displayOutput(Poincare::Context * context);
@@ -99,6 +100,7 @@ private:
static constexpr int k_numberOfExpressions = 4; static constexpr int k_numberOfExpressions = 4;
static constexpr KDCoordinate k_heightComputationFailureHeight = 50; static constexpr KDCoordinate k_heightComputationFailureHeight = 50;
static constexpr const char * k_maximalIntegerWithAdditionalInformation = "10000000000000000"; static constexpr const char * k_maximalIntegerWithAdditionalInformation = "10000000000000000";
void resetHeightMemoization();
/* Buffers holding text expressions have to be longer than the text written /* Buffers holding text expressions have to be longer than the text written
* by user (of maximum length TextField::maxBufferSize()) because when we * by user (of maximum length TextField::maxBufferSize()) because when we
* print an expression we add omitted signs (multiplications, parenthesis...) */ * print an expression we add omitted signs (multiplications, parenthesis...) */

View File

@@ -4,6 +4,7 @@
#include <poincare/rational.h> #include <poincare/rational.h>
#include <poincare/symbol.h> #include <poincare/symbol.h>
#include <poincare/undefined.h> #include <poincare/undefined.h>
#include "../exam_mode_configuration.h"
#include <assert.h> #include <assert.h>
using namespace Poincare; using namespace Poincare;
@@ -98,8 +99,11 @@ ExpiringPointer<Calculation> CalculationStore::push(const char * text, Context *
// Outputs hold exact output, approximate output and its duplicate // Outputs hold exact output, approximate output and its duplicate
constexpr static int numberOfOutputs = Calculation::k_numberOfExpressions - 1; constexpr static int numberOfOutputs = Calculation::k_numberOfExpressions - 1;
Expression outputs[numberOfOutputs] = {Expression(), Expression(), Expression()}; Expression outputs[numberOfOutputs] = {Expression(), Expression(), Expression()};
// SYMBOLIC COMPUTATION <= E12: PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, GlobalPreferences::sharedGlobalPreferences()->isInExamModeSymbolic()); // Symbolic computation
PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, GlobalPreferences::sharedGlobalPreferences()->isInExamModeSymbolic() ? Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition : Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); PoincareHelpers::ParseAndSimplifyAndApproximate(inputSerialization, &(outputs[0]), &(outputs[1]), context, GlobalPreferences::sharedGlobalPreferences()->isInExamModeSymbolic() ? Poincare::ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition : Poincare::ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined);
if (ExamModeConfiguration::exactExpressionsAreForbidden(GlobalPreferences::sharedGlobalPreferences()->examMode()) && outputs[1].hasUnit()) {
// Hide results with units on units if required by the exam mode configuration
outputs[1] = Undefined::Builder();
}
outputs[2] = outputs[1]; outputs[2] = outputs[1];
int numberOfSignificantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits; int numberOfSignificantDigits = Poincare::PrintFloat::k_numberOfStoredSignificantDigits;
for (int i = 0; i < numberOfOutputs; i++) { for (int i = 0; i < numberOfOutputs; i++) {

View File

@@ -9,7 +9,7 @@ using namespace Poincare;
namespace Calculation { namespace Calculation {
EditExpressionController::ContentView::ContentView(Responder * parentResponder, TableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) : EditExpressionController::ContentView::ContentView(Responder * parentResponder, CalculationSelectableTableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) :
View(), View(),
m_mainView(subview), m_mainView(subview),
m_expressionField(parentResponder, inputEventHandlerDelegate, textFieldDelegate, layoutFieldDelegate) m_expressionField(parentResponder, inputEventHandlerDelegate, textFieldDelegate, layoutFieldDelegate)
@@ -42,18 +42,18 @@ EditExpressionController::EditExpressionController(Responder * parentResponder,
ViewController(parentResponder), ViewController(parentResponder),
m_historyController(historyController), m_historyController(historyController),
m_calculationStore(calculationStore), m_calculationStore(calculationStore),
m_contentView(this, (TableView *)m_historyController->view(), inputEventHandlerDelegate, this, this) m_contentView(this, static_cast<CalculationSelectableTableView *>(m_historyController->view()), inputEventHandlerDelegate, this, this)
{ {
m_cacheBuffer[0] = 0; m_cacheBuffer[0] = 0;
} }
void EditExpressionController::insertTextBody(const char * text) { void EditExpressionController::insertTextBody(const char * text) {
Container::activeApp()->setFirstResponder(this);
m_contentView.expressionField()->handleEventWithText(text, false, true); m_contentView.expressionField()->handleEventWithText(text, false, true);
} }
void EditExpressionController::didBecomeFirstResponder() { void EditExpressionController::didBecomeFirstResponder() {
int lastRow = m_calculationStore->numberOfCalculations() > 0 ? m_calculationStore->numberOfCalculations()-1 : 0; m_contentView.mainView()->scrollToBottom();
m_historyController->scrollToCell(0, lastRow);
m_contentView.expressionField()->setEditing(true, false); m_contentView.expressionField()->setEditing(true, false);
Container::activeApp()->setFirstResponder(m_contentView.expressionField()); Container::activeApp()->setFirstResponder(m_contentView.expressionField());
} }

View File

@@ -8,6 +8,7 @@
#include "../shared/layout_field_delegate.h" #include "../shared/layout_field_delegate.h"
#include "history_controller.h" #include "history_controller.h"
#include "calculation_store.h" #include "calculation_store.h"
#include "selectable_table_view.h"
namespace Calculation { namespace Calculation {
@@ -34,15 +35,15 @@ public:
private: private:
class ContentView : public View { class ContentView : public View {
public: public:
ContentView(Responder * parentResponder, TableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate); ContentView(Responder * parentResponder, CalculationSelectableTableView * subview, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate);
void reload(); void reload();
TableView * mainView() { return m_mainView; } CalculationSelectableTableView * mainView() { return m_mainView; }
ExpressionField * expressionField() { return &m_expressionField; } ExpressionField * expressionField() { return &m_expressionField; }
private: private:
int numberOfSubviews() const override { return 2; } int numberOfSubviews() const override { return 2; }
View * subviewAtIndex(int index) override; View * subviewAtIndex(int index) override;
void layoutSubviews(bool force = false) override; void layoutSubviews(bool force = false) override;
TableView * m_mainView; CalculationSelectableTableView * m_mainView;
ExpressionField m_expressionField; ExpressionField m_expressionField;
}; };
void reloadView(); void reloadView();

View File

@@ -7,7 +7,10 @@ namespace Calculation {
class ExpressionField : public ::ExpressionField { class ExpressionField : public ::ExpressionField {
public: public:
using ::ExpressionField::ExpressionField; ExpressionField(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandler, TextFieldDelegate * textFieldDelegate, LayoutFieldDelegate * layoutFieldDelegate) :
::ExpressionField(parentResponder, inputEventHandler, textFieldDelegate, layoutFieldDelegate) {
setLayoutInsertionCursorEvent(Ion::Events::Up);
}
protected: protected:
bool handleEvent(Ion::Events::Event event) override; bool handleEvent(Ion::Events::Event event) override;
}; };

View File

@@ -1,5 +1,6 @@
#include "history_controller.h" #include "history_controller.h"
#include "app.h" #include "app.h"
#include <poincare/exception_checkpoint.h>
#include <assert.h> #include <assert.h>
using namespace Shared; using namespace Shared;
@@ -15,7 +16,8 @@ HistoryController::HistoryController(EditExpressionController * editExpressionCo
m_complexController(editExpressionController), m_complexController(editExpressionController),
m_integerController(editExpressionController), m_integerController(editExpressionController),
m_rationalController(editExpressionController), m_rationalController(editExpressionController),
m_trigonometryController(editExpressionController) m_trigonometryController(editExpressionController),
m_unitController(editExpressionController)
{ {
for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) { for (int i = 0; i < k_maxNumberOfDisplayedRows; i++) {
m_calculationHistory[i].setParentResponder(&m_selectableTableView); m_calculationHistory[i].setParentResponder(&m_selectableTableView);
@@ -37,9 +39,9 @@ void HistoryController::reload() {
* the table view twice. * the table view twice.
*/ */
if (numberOfRows() > 0) { if (numberOfRows() > 0) {
m_selectableTableView.scrollToCell(0, numberOfRows()-1); m_selectableTableView.scrollToBottom();
// Force to reload last added cell (hide the burger and exact output if necessary) // Force to reload last added cell (hide the burger and exact output if necessary)
tableViewDidChangeSelection(&m_selectableTableView, 0, numberOfRows()-1); tableViewDidChangeSelectionAndDidScroll(&m_selectableTableView, 0, numberOfRows()-1);
} }
} }
@@ -78,11 +80,9 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
EditExpressionController * editController = (EditExpressionController *)parentResponder(); EditExpressionController * editController = (EditExpressionController *)parentResponder();
if (subviewType == SubviewType::Input) { if (subviewType == SubviewType::Input) {
m_selectableTableView.deselectTable(); m_selectableTableView.deselectTable();
Container::activeApp()->setFirstResponder(editController);
editController->insertTextBody(calculationAtIndex(focusRow)->inputText()); editController->insertTextBody(calculationAtIndex(focusRow)->inputText());
} else if (subviewType == SubviewType::Output) { } else if (subviewType == SubviewType::Output) {
m_selectableTableView.deselectTable(); m_selectableTableView.deselectTable();
Container::activeApp()->setFirstResponder(editController);
Shared::ExpiringPointer<Calculation> calculation = calculationAtIndex(focusRow); Shared::ExpiringPointer<Calculation> calculation = calculationAtIndex(focusRow);
ScrollableTwoExpressionsView::SubviewPosition outputSubviewPosition = selectedCell->outputView()->selectedSubviewPosition(); ScrollableTwoExpressionsView::SubviewPosition outputSubviewPosition = selectedCell->outputView()->selectedSubviewPosition();
if (outputSubviewPosition == ScrollableTwoExpressionsView::SubviewPosition::Right if (outputSubviewPosition == ScrollableTwoExpressionsView::SubviewPosition::Right
@@ -108,6 +108,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
vc = &m_integerController; vc = &m_integerController;
} else if (additionalInfoType == Calculation::AdditionalInformationType::Rational) { } else if (additionalInfoType == Calculation::AdditionalInformationType::Rational) {
vc = &m_rationalController; vc = &m_rationalController;
} else if (additionalInfoType == Calculation::AdditionalInformationType::Unit) {
vc = &m_unitController;
} }
if (vc) { if (vc) {
vc->setExpression(e); vc->setExpression(e);
@@ -120,24 +122,14 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
int focusRow = selectedRow(); int focusRow = selectedRow();
SubviewType subviewType = selectedSubviewType(); SubviewType subviewType = selectedSubviewType();
m_selectableTableView.deselectTable(); m_selectableTableView.deselectTable();
EditExpressionController * editController = (EditExpressionController *)parentResponder();
m_calculationStore->deleteCalculationAtIndex(storeIndex(focusRow)); m_calculationStore->deleteCalculationAtIndex(storeIndex(focusRow));
reload(); reload();
if (numberOfRows()== 0) { if (numberOfRows()== 0) {
Container::activeApp()->setFirstResponder(editController); Container::activeApp()->setFirstResponder(parentResponder());
return true; return true;
} }
if (focusRow > 0) { m_selectableTableView.selectCellAtLocation(0, focusRow > 0 ? focusRow - 1 : 0);
m_selectableTableView.selectCellAtLocation(0, focusRow-1); setSelectedSubviewType(subviewType, true, 0, selectedRow());
} else {
m_selectableTableView.selectCellAtLocation(0, 0);
}
if (subviewType == SubviewType::Input) {
tableViewDidChangeSelection(&m_selectableTableView, 0, selectedRow());
} else {
tableViewDidChangeSelection(&m_selectableTableView, 0, -1);
}
m_selectableTableView.scrollToCell(0, selectedRow());
return true; return true;
} }
if (event == Ion::Events::Clear) { if (event == Ion::Events::Clear) {
@@ -148,9 +140,8 @@ bool HistoryController::handleEvent(Ion::Events::Event event) {
return true; return true;
} }
if (event == Ion::Events::Back) { if (event == Ion::Events::Back) {
EditExpressionController * editController = (EditExpressionController *)parentResponder();
m_selectableTableView.deselectTable(); m_selectableTableView.deselectTable();
Container::activeApp()->setFirstResponder(editController); Container::activeApp()->setFirstResponder(parentResponder());
return true; return true;
} }
return false; return false;
@@ -160,19 +151,23 @@ Shared::ExpiringPointer<Calculation> HistoryController::calculationAtIndex(int i
return m_calculationStore->calculationAtIndex(storeIndex(i)); return m_calculationStore->calculationAtIndex(storeIndex(i));
} }
void HistoryController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { void HistoryController::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
if (withinTemporarySelection || previousSelectedCellY == selectedRow()) { if (withinTemporarySelection || previousSelectedCellY == selectedRow()) {
return; return;
} }
if (previousSelectedCellY == -1) { if (previousSelectedCellY == -1) {
setSelectedSubviewType(SubviewType::Output, false, previousSelectedCellX, previousSelectedCellY); setSelectedSubviewType(SubviewType::Output, false, previousSelectedCellX, previousSelectedCellY);
} else if (selectedRow() < previousSelectedCellY) {
setSelectedSubviewType(SubviewType::Output, false, previousSelectedCellX, previousSelectedCellY);
} else if (selectedRow() > previousSelectedCellY) {
setSelectedSubviewType(SubviewType::Input, false, previousSelectedCellX, previousSelectedCellY);
} else if (selectedRow() == -1) { } else if (selectedRow() == -1) {
setSelectedSubviewType(SubviewType::Input, false, previousSelectedCellX, previousSelectedCellY); setSelectedSubviewType(SubviewType::Input, false, previousSelectedCellX, previousSelectedCellY);
} else {
HistoryViewCell * selectedCell = (HistoryViewCell *)(t->selectedCell());
SubviewType nextSelectedSubviewType = selectedSubviewType();
if (selectedCell && !selectedCell->displaysSingleLine()) {
nextSelectedSubviewType = previousSelectedCellY < selectedRow() ? SubviewType::Input : SubviewType::Output;
}
setSelectedSubviewType(nextSelectedSubviewType, false, previousSelectedCellX, previousSelectedCellY);
} }
// The selectedCell may change during setSelectedSubviewType
HistoryViewCell * selectedCell = (HistoryViewCell *)(t->selectedCell()); HistoryViewCell * selectedCell = (HistoryViewCell *)(t->selectedCell());
if (selectedCell == nullptr) { if (selectedCell == nullptr) {
return; return;
@@ -208,22 +203,42 @@ KDCoordinate HistoryController::rowHeight(int j) {
return 0; return 0;
} }
Shared::ExpiringPointer<Calculation> calculation = calculationAtIndex(j); Shared::ExpiringPointer<Calculation> calculation = calculationAtIndex(j);
return calculation->height(App::app()->localContext(), j == selectedRow() && selectedSubviewType() == SubviewType::Output); bool expanded = j == selectedRow() && selectedSubviewType() == SubviewType::Output;
KDCoordinate result = calculation->memoizedHeight(expanded);
if (result < 0) {
result = HistoryViewCell::Height(calculation.pointer(), expanded);
if (result < 0) {
// Raise, because Height modified the calculation and failed.
Poincare::ExceptionCheckpoint::Raise();
}
calculation->setMemoizedHeight(expanded, result);
}
/* We might want to put an assertion here to check the memoization:
* assert(result == HistoryViewCell::Height(calculation.pointer(), expanded));
* However, Height might fail due to pool memory exhaustion, in which case the
* assertion fails even if "result" had the right value. */
return result;
} }
int HistoryController::typeAtLocation(int i, int j) { int HistoryController::typeAtLocation(int i, int j) {
return 0; return 0;
} }
void HistoryController::scrollToCell(int i, int j) {
m_selectableTableView.scrollToCell(i, j);
}
bool HistoryController::calculationAtIndexToggles(int index) { bool HistoryController::calculationAtIndexToggles(int index) {
Context * context = App::app()->localContext(); Context * context = App::app()->localContext();
return index >= 0 && index < m_calculationStore->numberOfCalculations() && calculationAtIndex(index)->displayOutput(context) == Calculation::DisplayOutput::ExactAndApproximateToggle; return index >= 0 && index < m_calculationStore->numberOfCalculations() && calculationAtIndex(index)->displayOutput(context) == Calculation::DisplayOutput::ExactAndApproximateToggle;
} }
void HistoryController::setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX, int previousSelectedY) {
// Avoid selecting non-displayed ellipsis
HistoryViewCell * selectedCell = static_cast<HistoryViewCell *>(m_selectableTableView.selectedCell());
if (subviewType == SubviewType::Ellipsis && selectedCell && selectedCell->additionalInformationType() == Calculation::AdditionalInformationType::None) {
subviewType = SubviewType::Output;
}
HistoryViewCellDataSource::setSelectedSubviewType(subviewType, sameCell, previousSelectedX, previousSelectedY);
}
void HistoryController::historyViewCellDidChangeSelection(HistoryViewCell ** cell, HistoryViewCell ** previousCell, int previousSelectedCellX, int previousSelectedCellY, SubviewType type, SubviewType previousType) { void HistoryController::historyViewCellDidChangeSelection(HistoryViewCell ** cell, HistoryViewCell ** previousCell, int previousSelectedCellX, int previousSelectedCellY, SubviewType type, SubviewType previousType) {
/* If the selection change triggers the toggling of the outputs, we update /* If the selection change triggers the toggling of the outputs, we update
* the whole table as the height of the selected cell row might have changed. */ * the whole table as the height of the selected cell row might have changed. */

View File

@@ -9,6 +9,7 @@
#include "additional_outputs/integer_list_controller.h" #include "additional_outputs/integer_list_controller.h"
#include "additional_outputs/rational_list_controller.h" #include "additional_outputs/rational_list_controller.h"
#include "additional_outputs/trigonometry_list_controller.h" #include "additional_outputs/trigonometry_list_controller.h"
#include "additional_outputs/unit_list_controller.h"
namespace Calculation { namespace Calculation {
@@ -30,8 +31,8 @@ public:
void willDisplayCellForIndex(HighlightCell * cell, int index) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override;
KDCoordinate rowHeight(int j) override; KDCoordinate rowHeight(int j) override;
int typeAtLocation(int i, int j) override; int typeAtLocation(int i, int j) override;
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override; void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1) override;
void scrollToCell(int i, int j); void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection = false) override;
private: private:
int storeIndex(int i) { return numberOfRows() - i - 1; } int storeIndex(int i) { return numberOfRows() - i - 1; }
Shared::ExpiringPointer<Calculation> calculationAtIndex(int i); Shared::ExpiringPointer<Calculation> calculationAtIndex(int i);
@@ -46,6 +47,7 @@ private:
IntegerListController m_integerController; IntegerListController m_integerController;
RationalListController m_rationalController; RationalListController m_rationalController;
TrigonometryListController m_trigonometryController; TrigonometryListController m_trigonometryController;
UnitListController m_unitController;
}; };
} }

View File

@@ -5,17 +5,12 @@
#include <poincare/exception_checkpoint.h> #include <poincare/exception_checkpoint.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <algorithm>
namespace Calculation { namespace Calculation {
static inline KDCoordinate minCoordinate(KDCoordinate x, KDCoordinate y) { return x < y ? x : y; }
static inline KDCoordinate maxCoordinate(KDCoordinate x, KDCoordinate y) { return x > y ? x : y; }
/* HistoryViewCellDataSource */ /* HistoryViewCellDataSource */
HistoryViewCellDataSource::HistoryViewCellDataSource() :
m_selectedSubviewType(SubviewType::Output) {}
void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedCellX, int previousSelectedCellY) { void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedCellX, int previousSelectedCellY) {
HistoryViewCell * selectedCell = nullptr; HistoryViewCell * selectedCell = nullptr;
HistoryViewCell * previouslySelectedCell = nullptr; HistoryViewCell * previouslySelectedCell = nullptr;
@@ -30,6 +25,7 @@ void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType,
if (selectedCell) { if (selectedCell) {
selectedCell->reloadSubviewHighlight(); selectedCell->reloadSubviewHighlight();
selectedCell->cellDidSelectSubview(subviewType, previousSubviewType); selectedCell->cellDidSelectSubview(subviewType, previousSubviewType);
Container::activeApp()->setFirstResponder(selectedCell);
} }
if (previouslySelectedCell) { if (previouslySelectedCell) {
previouslySelectedCell->cellDidSelectSubview(SubviewType::Input); previouslySelectedCell->cellDidSelectSubview(SubviewType::Input);
@@ -38,19 +34,35 @@ void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType,
/* HistoryViewCell */ /* HistoryViewCell */
HistoryViewCell::HistoryViewCell(Responder * parentResponder) : KDCoordinate HistoryViewCell::Height(Calculation * calculation, bool expanded) {
Responder(parentResponder), HistoryViewCell cell(nullptr);
m_calculationDisplayOutput(Calculation::DisplayOutput::Unknown), bool didForceOutput = false;
m_calculationAdditionInformation(Calculation::AdditionalInformationType::None), cell.setCalculation(calculation, expanded, &didForceOutput);
m_calculationExpanded(false), if (didForceOutput) {
m_inputView(this, Metric::CommonLargeMargin, Metric::CommonSmallMargin), /* We could not compute the height of the calculation as it is (the display
m_scrollableOutputView(this) * output was forced to another value during the height computation).
{ * Warning: the display output of calculation was actually changed, so it
m_calculationCRC32 = 0; * will cause problems if we already did some computations with another
* display value. */
return -1;
}
KDRect ellipsisFrame = KDRectZero;
KDRect inputFrame = KDRectZero;
KDRect outputFrame = KDRectZero;
cell.computeSubviewFrames(Ion::Display::Width, KDCOORDINATE_MAX, &ellipsisFrame, &inputFrame, &outputFrame);
return k_margin + inputFrame.unionedWith(outputFrame).height() + k_margin;
} }
Shared::ScrollableTwoExpressionsView * HistoryViewCell::outputView() { HistoryViewCell::HistoryViewCell(Responder * parentResponder) :
return &m_scrollableOutputView; Responder(parentResponder),
m_calculationCRC32(0),
m_calculationDisplayOutput(Calculation::DisplayOutput::Unknown),
m_calculationAdditionInformation(Calculation::AdditionalInformationType::None),
m_inputView(this, k_inputViewHorizontalMargin, k_inputOutputViewsVerticalMargin),
m_scrollableOutputView(this),
m_calculationExpanded(false),
m_calculationSingleLine(false)
{
} }
void HistoryViewCell::setEven(bool even) { void HistoryViewCell::setEven(bool even) {
@@ -138,15 +150,6 @@ void HistoryViewCell::cellDidSelectSubview(HistoryViewCellDataSource::SubviewTyp
reloadScroll(); reloadScroll();
} }
KDColor HistoryViewCell::backgroundColor() const {
KDColor background = m_even ? Palette::CalculationBackgroundEven : Palette::CalculationBackgroundOdd;
return background;
}
int HistoryViewCell::numberOfSubviews() const {
return 2 + displayedEllipsis();
}
View * HistoryViewCell::subviewAtIndex(int index) { View * HistoryViewCell::subviewAtIndex(int index) {
/* The order of the subviews should not matter here as they don't overlap. /* The order of the subviews should not matter here as they don't overlap.
* However, the order determines the order of redrawing as well. For several * However, the order determines the order of redrawing as well. For several
@@ -170,29 +173,69 @@ View * HistoryViewCell::subviewAtIndex(int index) {
return views[index]; return views[index];
} }
bool HistoryViewCell::ViewsCanBeSingleLine(KDCoordinate inputViewWidth, KDCoordinate outputViewWidth) {
// k_margin is the separation between the input and output.
return (inputViewWidth + k_margin + outputViewWidth) < Ion::Display::Width - Metric::EllipsisCellWidth;
}
void HistoryViewCell::layoutSubviews(bool force) { void HistoryViewCell::layoutSubviews(bool force) {
KDCoordinate maxFrameWidth = bounds().width(); KDRect frameBounds = bounds();
if (displayedEllipsis()) { if (bounds().width() <= 0 || bounds().height() <= 0) {
m_ellipsis.setFrame(KDRect(maxFrameWidth - Metric::EllipsisCellWidth, 0, Metric::EllipsisCellWidth, bounds().height()), force); // TODO Make this behaviour in a non-virtual layoutSublviews, and all layout subviews should become privateLayoutSubviews
maxFrameWidth -= Metric::EllipsisCellWidth; return;
} else {
m_ellipsis.setFrame(KDRectZero, force); // Required to mark previous rect as dirty
} }
KDRect ellipsisFrame = KDRectZero;
KDRect inputFrame = KDRectZero;
KDRect outputFrame = KDRectZero;
computeSubviewFrames(frameBounds.width(), frameBounds.height(), &ellipsisFrame, &inputFrame, &outputFrame);
m_ellipsis.setFrame(ellipsisFrame, force); // Required even if ellipsisFrame is KDRectZero, to mark previous rect as dirty
m_inputView.setFrame(inputFrame,force);
m_scrollableOutputView.setFrame(outputFrame, force);
}
void HistoryViewCell::computeSubviewFrames(KDCoordinate frameWidth, KDCoordinate frameHeight, KDRect * ellipsisFrame, KDRect * inputFrame, KDRect * outputFrame) {
assert(ellipsisFrame != nullptr && inputFrame != nullptr && outputFrame != nullptr);
if (displayedEllipsis()) {
*ellipsisFrame = KDRect(frameWidth - Metric::EllipsisCellWidth, 0, Metric::EllipsisCellWidth, frameHeight);
frameWidth -= Metric::EllipsisCellWidth;
} else {
*ellipsisFrame = KDRectZero;
}
KDSize inputSize = m_inputView.minimalSizeForOptimalDisplay(); KDSize inputSize = m_inputView.minimalSizeForOptimalDisplay();
m_inputView.setFrame(KDRect(
0, 0,
minCoordinate(maxFrameWidth, inputSize.width()),
inputSize.height()),
force);
KDSize outputSize = m_scrollableOutputView.minimalSizeForOptimalDisplay(); KDSize outputSize = m_scrollableOutputView.minimalSizeForOptimalDisplay();
int singleLine = outputSize.width() + inputSize.width() < bounds().width() - 6;
int outputHeight = (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact) ? (maxCoordinate(0, inputSize.height() - outputSize.height()) / 2) + maxCoordinate(0, (inputSize.height() - outputSize.height()) / 2) : inputSize.height(); /* To compute if the calculation is on a single line, use the expanded width
m_scrollableOutputView.setFrame(KDRect( * if there is both an exact and an approximate layout. */
maxCoordinate(0, maxFrameWidth - outputSize.width()), m_calculationSingleLine = ViewsCanBeSingleLine(inputSize.width(), m_scrollableOutputView.minimalSizeForOptimalDisplayFullSize().width());
outputHeight,
minCoordinate(maxFrameWidth, outputSize.width()), KDCoordinate inputY = k_margin;
outputSize.height()), KDCoordinate outputY = k_margin;
force); if (m_calculationSingleLine && !m_inputView.layout().isUninitialized()) {
KDCoordinate inputBaseline = m_inputView.layout().baseline();
KDCoordinate outputBaseline = m_scrollableOutputView.baseline();
KDCoordinate baselineDifference = outputBaseline - inputBaseline;
if (baselineDifference > 0) {
inputY += baselineDifference;
} else {
outputY += -baselineDifference;
}
} else {
outputY += inputSize.height();
}
*inputFrame = KDRect(
0,
inputY,
std::min(frameWidth, inputSize.width()),
inputSize.height());
*outputFrame = KDRect(
std::max(0, frameWidth - outputSize.width()),
outputY,
std::min(frameWidth, outputSize.width()),
outputSize.height());
} }
void HistoryViewCell::resetMemoization() { void HistoryViewCell::resetMemoization() {
@@ -203,7 +246,8 @@ void HistoryViewCell::resetMemoization() {
m_calculationCRC32 = 0; m_calculationCRC32 = 0;
} }
void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) { void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput) {
assert(!didForceOutput || *didForceOutput == false);
uint32_t newCalculationCRC = Ion::crc32Byte((const uint8_t *)calculation, ((char *)calculation->next()) - ((char *) calculation)); uint32_t newCalculationCRC = Ion::crc32Byte((const uint8_t *)calculation, ((char *)calculation->next()) - ((char *) calculation));
if (newCalculationCRC == m_calculationCRC32 && m_calculationExpanded == expanded) { if (newCalculationCRC == m_calculationCRC32 && m_calculationExpanded == expanded) {
return; return;
@@ -231,6 +275,9 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) {
if (couldNotCreateExactLayout) { if (couldNotCreateExactLayout) {
if (calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) { if (calculation->displayOutput(context) != ::Calculation::Calculation::DisplayOutput::ExactOnly) {
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
} else { } else {
/* We should only display the exact result, but we cannot create it /* We should only display the exact result, but we cannot create it
* -> raise an exception. */ * -> raise an exception. */
@@ -253,6 +300,9 @@ void HistoryViewCell::setCalculation(Calculation * calculation, bool expanded) {
/* Set the display output to ApproximateOnly, make room in the pool by /* Set the display output to ApproximateOnly, make room in the pool by
* erasing the exact layout, and retry to create the approximate layout */ * erasing the exact layout, and retry to create the approximate layout */
calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly); calculation->forceDisplayOutput(::Calculation::Calculation::DisplayOutput::ApproximateOnly);
if (didForceOutput) {
*didForceOutput = true;
}
exactOutputLayout = Poincare::Layout(); exactOutputLayout = Poincare::Layout();
couldNotCreateApproximateLayout = false; couldNotCreateApproximateLayout = false;
approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout); approximateOutputLayout = calculation->createApproximateOutputLayout(context, &couldNotCreateApproximateLayout);
@@ -286,31 +336,41 @@ void HistoryViewCell::didBecomeFirstResponder() {
} }
bool HistoryViewCell::handleEvent(Ion::Events::Event event) { bool HistoryViewCell::handleEvent(Ion::Events::Event event) {
assert(m_dataSource); assert(m_dataSource != nullptr);
HistoryViewCellDataSource::SubviewType type = m_dataSource->selectedSubviewType(); HistoryViewCellDataSource::SubviewType type = m_dataSource->selectedSubviewType();
if ((event == Ion::Events::Down && type == HistoryViewCellDataSource::SubviewType::Input) || assert(type != HistoryViewCellDataSource::SubviewType::None);
(event == Ion::Events::Up && type == HistoryViewCellDataSource::SubviewType::Output) || HistoryViewCellDataSource::SubviewType otherSubviewType = HistoryViewCellDataSource::SubviewType::None;
(event == Ion::Events::Right && type != HistoryViewCellDataSource::SubviewType::Ellipsis && displayedEllipsis()) || if (m_calculationSingleLine) {
(event == Ion::Events::Left && type == HistoryViewCellDataSource::SubviewType::Ellipsis)) { static_assert(
HistoryViewCellDataSource::SubviewType otherSubviewType; static_cast<int>(HistoryViewCellDataSource::SubviewType::None) == 0
if (event == Ion::Events::Down) { && static_cast<int>(HistoryViewCellDataSource::SubviewType::Input) == 1
otherSubviewType = HistoryViewCellDataSource::SubviewType::Output; && static_cast<int>(HistoryViewCellDataSource::SubviewType::Output) == 2
} else if (event == Ion::Events::Up) { && static_cast<int>(HistoryViewCellDataSource::SubviewType::Ellipsis) == 3,
otherSubviewType = HistoryViewCellDataSource::SubviewType::Input; "The array types is not well-formed anymore");
} else if (event == Ion::Events::Right) { HistoryViewCellDataSource::SubviewType types[] = {
otherSubviewType = HistoryViewCellDataSource::SubviewType::Ellipsis; HistoryViewCellDataSource::SubviewType::None,
} else { HistoryViewCellDataSource::SubviewType::Input,
assert(event == Ion::Events::Left); HistoryViewCellDataSource::SubviewType::Output,
otherSubviewType = HistoryViewCellDataSource::SubviewType::Output; displayedEllipsis() ? HistoryViewCellDataSource::SubviewType::Ellipsis : HistoryViewCellDataSource::SubviewType::None,
HistoryViewCellDataSource::SubviewType::None,
};
if (event == Ion::Events::Right || event == Ion::Events::Left) {
otherSubviewType = types[static_cast<int>(type) + (event == Ion::Events::Right ? 1 : -1)];
} }
m_dataSource->setSelectedSubviewType(otherSubviewType, true); } else if ((event == Ion::Events::Down && type == HistoryViewCellDataSource::SubviewType::Input)
return true; || (event == Ion::Events::Left && type == HistoryViewCellDataSource::SubviewType::Ellipsis))
{
otherSubviewType = HistoryViewCellDataSource::SubviewType::Output;
} else if (event == Ion::Events::Up && type == HistoryViewCellDataSource::SubviewType::Output) {
otherSubviewType = HistoryViewCellDataSource::SubviewType::Input;
} else if (event == Ion::Events::Right && type != HistoryViewCellDataSource::SubviewType::Ellipsis && displayedEllipsis()) {
otherSubviewType = HistoryViewCellDataSource::SubviewType::Ellipsis;
} }
return false; if (otherSubviewType == HistoryViewCellDataSource::SubviewType::None) {
} return false;
}
bool HistoryViewCell::displayedEllipsis() const { m_dataSource->setSelectedSubviewType(otherSubviewType, true);
return m_highlighted && m_calculationAdditionInformation != Calculation::AdditionalInformationType::None; return true;
} }
} }

View File

@@ -12,14 +12,14 @@ class HistoryViewCell;
class HistoryViewCellDataSource { class HistoryViewCellDataSource {
public: public:
enum class SubviewType { enum class SubviewType {
None, None = 0,
Input, Input = 1,
Output, Output = 2,
Ellipsis Ellipsis = 3
}; };
HistoryViewCellDataSource(); HistoryViewCellDataSource() : m_selectedSubviewType(SubviewType::Output) {}
void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1); virtual void setSelectedSubviewType(SubviewType subviewType, bool sameCell, int previousSelectedX = -1, int previousSelectedY = -1);
SubviewType selectedSubviewType() { return m_selectedSubviewType; } SubviewType selectedSubviewType() const { return m_selectedSubviewType; }
private: private:
/* This method should belong to a delegate instead of a data source but as /* This method should belong to a delegate instead of a data source but as
* both the data source and the delegate will be the same controller, we * both the data source and the delegate will be the same controller, we
@@ -31,39 +31,52 @@ private:
class HistoryViewCell : public ::EvenOddCell, public Responder { class HistoryViewCell : public ::EvenOddCell, public Responder {
public: public:
constexpr static KDCoordinate k_margin = Metric::CommonSmallMargin;
constexpr static KDCoordinate k_inputOutputViewsVerticalMargin = k_margin;
constexpr static KDCoordinate k_inputViewHorizontalMargin = Shared::AbstractScrollableMultipleExpressionsView::k_horizontalMargin;
static KDCoordinate Height(Calculation * calculation, bool expanded);
HistoryViewCell(Responder * parentResponder = nullptr); HistoryViewCell(Responder * parentResponder = nullptr);
static bool ViewsCanBeSingleLine(KDCoordinate inputViewWidth, KDCoordinate outputViewWidth);
void cellDidSelectSubview(HistoryViewCellDataSource::SubviewType type, HistoryViewCellDataSource::SubviewType previousType = HistoryViewCellDataSource::SubviewType::None); void cellDidSelectSubview(HistoryViewCellDataSource::SubviewType type, HistoryViewCellDataSource::SubviewType previousType = HistoryViewCellDataSource::SubviewType::None);
void setEven(bool even) override; void setEven(bool even) override;
void setHighlighted(bool highlight) override; void setHighlighted(bool highlight) override;
void reloadSubviewHighlight(); void reloadSubviewHighlight();
void setDataSource(HistoryViewCellDataSource * dataSource) { m_dataSource = dataSource; } void setDataSource(HistoryViewCellDataSource * dataSource) { m_dataSource = dataSource; }
bool displaysSingleLine() const {
return m_calculationSingleLine;
}
Responder * responder() override { Responder * responder() override {
return this; return this;
} }
Poincare::Layout layout() const override; Poincare::Layout layout() const override;
KDColor backgroundColor() const override; KDColor backgroundColor() const override { return m_even ? Palette::CalculationBackgroundEven : Palette::CalculationBackgroundOdd; }
void resetMemoization(); void resetMemoization();
void setCalculation(Calculation * calculation, bool expanded); void setCalculation(Calculation * calculation, bool expanded, bool * didForceOutput = nullptr);
int numberOfSubviews() const override; int numberOfSubviews() const override { return 2 + displayedEllipsis(); }
View * subviewAtIndex(int index) override; View * subviewAtIndex(int index) override;
void layoutSubviews(bool force = false) override; void layoutSubviews(bool force = false) override;
void didBecomeFirstResponder() override; void didBecomeFirstResponder() override;
bool handleEvent(Ion::Events::Event event) override; bool handleEvent(Ion::Events::Event event) override;
Shared::ScrollableTwoExpressionsView * outputView(); Shared::ScrollableTwoExpressionsView * outputView() { return &m_scrollableOutputView; }
ScrollableExpressionView * inputView() { return &m_inputView; }
Calculation::AdditionalInformationType additionalInformationType() const { return m_calculationAdditionInformation; } Calculation::AdditionalInformationType additionalInformationType() const { return m_calculationAdditionInformation; }
private: private:
constexpr static KDCoordinate k_resultWidth = 80; constexpr static KDCoordinate k_resultWidth = 80;
void computeSubviewFrames(KDCoordinate frameWidth, KDCoordinate frameHeight, KDRect * ellipsisFrame, KDRect * inputFrame, KDRect * outputFrame);
void reloadScroll(); void reloadScroll();
void reloadOutputSelection(HistoryViewCellDataSource::SubviewType previousType); void reloadOutputSelection(HistoryViewCellDataSource::SubviewType previousType);
bool displayedEllipsis() const; bool displayedEllipsis() const {
return m_highlighted && m_calculationAdditionInformation != Calculation::AdditionalInformationType::None;
}
uint32_t m_calculationCRC32; uint32_t m_calculationCRC32;
Calculation::DisplayOutput m_calculationDisplayOutput; Calculation::DisplayOutput m_calculationDisplayOutput;
Calculation::AdditionalInformationType m_calculationAdditionInformation; Calculation::AdditionalInformationType m_calculationAdditionInformation;
bool m_calculationExpanded;
ScrollableExpressionView m_inputView; ScrollableExpressionView m_inputView;
Shared::ScrollableTwoExpressionsView m_scrollableOutputView; Shared::ScrollableTwoExpressionsView m_scrollableOutputView;
EvenOddCellWithEllipsis m_ellipsis; EvenOddCellWithEllipsis m_ellipsis;
HistoryViewCellDataSource * m_dataSource; HistoryViewCellDataSource * m_dataSource;
bool m_calculationExpanded;
bool m_calculationSingleLine;
}; };
} }

View File

@@ -1,4 +1,5 @@
#include "selectable_table_view.h" #include "selectable_table_view.h"
#include <algorithm>
namespace Calculation { namespace Calculation {
@@ -11,18 +12,23 @@ CalculationSelectableTableView::CalculationSelectableTableView(Responder * paren
setDecoratorType(ScrollView::Decorator::Type::None); setDecoratorType(ScrollView::Decorator::Type::None);
} }
void CalculationSelectableTableView::scrollToBottom() {
KDCoordinate contentOffsetX = contentOffset().x();
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(dataSource()->numberOfRows()) - maxContentHeightDisplayableWithoutScrolling();
setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
}
void CalculationSelectableTableView::scrollToCell(int i, int j) { void CalculationSelectableTableView::scrollToCell(int i, int j) {
::SelectableTableView::scrollToCell(i, j);
if (m_contentView.bounds().height() < bounds().height()) { if (m_contentView.bounds().height() < bounds().height()) {
setTopMargin(bounds().height() - m_contentView.bounds().height()); setTopMargin(bounds().height() - m_contentView.bounds().height());
} else { } else {
setTopMargin(0); setTopMargin(0);
} }
::SelectableTableView::scrollToCell(i, j);
ScrollView::layoutSubviews(); ScrollView::layoutSubviews();
if (m_contentView.bounds().height() - contentOffset().y() < bounds().height()) { if (m_contentView.bounds().height() - contentOffset().y() < bounds().height()) {
KDCoordinate contentOffsetX = contentOffset().x(); // Avoid empty space at the end of the table
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(dataSource()->numberOfRows()) - maxContentHeightDisplayableWithoutScrolling(); scrollToBottom();
setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
} }
} }
@@ -31,23 +37,63 @@ void CalculationSelectableTableView::scrollToSubviewOfTypeOfCellAtLocation(Histo
return; return;
} }
/* As we scroll, the selected calculation does not use the same history view /* As we scroll, the selected calculation does not use the same history view
* cell, thus, we want to deselect the previous used history view cell. */ * cell, thus, we want to deselect the previous used history view cell. (*) */
unhighlightSelectedCell(); unhighlightSelectedCell();
/* Main part of the scroll */ /* Main part of the scroll */
HistoryViewCell * cell = static_cast<HistoryViewCell *>(selectedCell());
assert(cell);
KDCoordinate contentOffsetX = contentOffset().x(); KDCoordinate contentOffsetX = contentOffset().x();
KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j+1) - maxContentHeightDisplayableWithoutScrolling();
if (subviewType == HistoryViewCellDataSource::SubviewType::Input) { KDCoordinate contentOffsetY = dataSource()->cumulatedHeightFromIndex(j);
if (j == 0) { if (cell->displaysSingleLine() && dataSource()->rowHeight(j) > maxContentHeightDisplayableWithoutScrolling()) {
contentOffsetY = 0; /* If we cannot display the full calculation, we display the selected
} else { * layout as close as possible to the top of the screen without drawing
contentOffsetY = dataSource()->cumulatedHeightFromIndex(j); * empty space between the history and the input field.
} *
* Below are some values we can assign to contentOffsetY, and the kinds of
* display they entail :
* (the selected cell is at index j)
*
* 1 - cumulatedHeightFromIndex(j)
* Aligns the top of the cell with the top of the zone in which the
* history can be drawn.
*
* 2 - (cumulatedHeightFromIndex(j+1)
* - maxContentHeightDisplayableWithoutScrolling())
* Aligns the bottom of the cell with the top of the input field.
*
* 3 - cumulatedHeightFromIndex(j) + baseline1 - baseline2
* Aligns the top of the selected layout with the top of the screen (only
* used when the selected layout is the smallest).
*
* The following drawing shows where the calculation would be aligned with
* each value of contentOffsetY, for the calculation (1/3)/(4/2) = 1/6.
*
* (1) (2) (3)
* +--------------+ +--------------+ +--------------+
* | 1 | | --- - | | 3 1 |
* | - | | 4 6 | | --- - |
* | 3 1 | | - | | 4 6 |
* | --- - | | 2 | | - |
* +--------------+ +--------------+ +--------------+
* | (1/3)/(4/2) | | (1/3)/(4/2) | | (1/3)/(4/2) |
* +--------------+ +--------------+ +--------------+
*
* */
contentOffsetY += std::min(
dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling(),
std::max(0, (cell->inputView()->layout().baseline() - cell->outputView()->baseline()) * (subviewType == HistoryViewCellDataSource::SubviewType::Input ? -1 : 1)));
} else if (subviewType != HistoryViewCellDataSource::SubviewType::Input) {
contentOffsetY += dataSource()->rowHeight(j) - maxContentHeightDisplayableWithoutScrolling();
} }
setContentOffset(KDPoint(contentOffsetX, contentOffsetY)); setContentOffset(KDPoint(contentOffsetX, contentOffsetY));
/* For the same reason, we have to rehighlight the new history view cell and /* For the same reason as (*), we have to rehighlight the new history view
* reselect the first responder. */ * cell and reselect the first responder.
HistoryViewCell * cell = (HistoryViewCell *)(selectedCell()); * We have to recall "selectedCell" because when the table might have been
* relayouted in "setContentOffset".*/
cell = static_cast<HistoryViewCell *>(selectedCell());
assert(cell); assert(cell);
cell->setHighlighted(true); cell->setHighlighted(true);
Container::activeApp()->setFirstResponder(cell); Container::activeApp()->setFirstResponder(cell);

View File

@@ -9,6 +9,7 @@ class CalculationSelectableTableView : public ::SelectableTableView {
public: public:
CalculationSelectableTableView(Responder * parentResponder, TableViewDataSource * dataSource, CalculationSelectableTableView(Responder * parentResponder, TableViewDataSource * dataSource,
SelectableTableViewDataSource * selectionDataSource, SelectableTableViewDelegate * delegate = nullptr); SelectableTableViewDataSource * selectionDataSource, SelectableTableViewDelegate * delegate = nullptr);
void scrollToBottom();
void scrollToCell(int i, int j) override; void scrollToCell(int i, int j) override;
void scrollToSubviewOfTypeOfCellAtLocation(HistoryViewCellDataSource::SubviewType subviewType, int i, int j); void scrollToSubviewOfTypeOfCellAtLocation(HistoryViewCellDataSource::SubviewType subviewType, int i, int j);
}; };

View File

@@ -11,42 +11,31 @@ app_code_src = $(addprefix apps/code/,\
editor_view.cpp \ editor_view.cpp \
helpers.cpp \ helpers.cpp \
menu_controller.cpp \ menu_controller.cpp \
python_toolbox.cpp \
python_text_area.cpp \ python_text_area.cpp \
sandbox_controller.cpp \ sandbox_controller.cpp \
script.cpp \
script_name_cell.cpp \ script_name_cell.cpp \
script_node_cell.cpp \
script_parameter_controller.cpp \ script_parameter_controller.cpp \
)
app_code_test_src = $(addprefix apps/code/,\
python_toolbox.cpp \
script.cpp \
script_node_cell.cpp \
script_store.cpp \ script_store.cpp \
script_template.cpp \ script_template.cpp \
variable_box_empty_controller.cpp \
variable_box_controller.cpp \ variable_box_controller.cpp \
) )
app_src += $(app_code_src) tests_src += $(addprefix apps/code/test/,\
variable_box_controller.cpp\
i18n_files += $(addprefix apps/code/,\
base.de.i18n\
base.en.i18n\
base.es.i18n\
base.fr.i18n\
base.pt.i18n\
base.hu.i18n\
base.universal.i18n\
catalog.de.i18n\
catalog.en.i18n\
catalog.es.i18n\
catalog.fr.i18n\
catalog.pt.i18n\
catalog.hu.i18n\
catalog.universal.i18n\
toolbox.de.i18n\
toolbox.en.i18n\
toolbox.es.i18n\
toolbox.fr.i18n\
toolbox.pt.i18n\
toolbox.hu.i18n\
toolbox.universal.i18n\
) )
app_code_src += $(app_code_test_src)
apps_src += $(app_code_src)
i18n_files += $(call i18n_with_universal_for,code/base)
i18n_files += $(call i18n_with_universal_for,code/catalog)
i18n_files += $(call i18n_with_universal_for,code/toolbox)
$(eval $(call depends_on_image,apps/code/app.cpp,apps/code/code_icon.png)) $(eval $(call depends_on_image,apps/code/app.cpp,apps/code/code_icon.png))

View File

@@ -14,8 +14,8 @@ I18n::Message App::Descriptor::upperName() {
return I18n::Message::CodeAppCapital; return I18n::Message::CodeAppCapital;
} }
int App::Descriptor::examinationLevel() { App::Descriptor::ExaminationLevel App::Descriptor::examinationLevel() {
return App::Descriptor::BasicExaminationLevel; return App::Descriptor::ExaminationLevel::Basic;
} }
const Image * App::Descriptor::icon() { const Image * App::Descriptor::icon() {
@@ -67,7 +67,7 @@ void App::Snapshot::setOpt(const char * name, const char * value) {
const char * scriptContent = separator; const char * scriptContent = separator;
Code::ScriptTemplate script(scriptName, scriptContent); Code::ScriptTemplate script(scriptName, scriptContent);
m_scriptStore.addScriptFromTemplate(&script); m_scriptStore.addScriptFromTemplate(&script);
m_scriptStore.scriptNamed(scriptName).toggleImportationStatus(); // set Importation Status to 1 ScriptStore::ScriptNamed(scriptName).toggleAutoimportationStatus(); // set Importation Status to 1
return; return;
} }
if (strcmp(name, "lock-on-console") == 0) { if (strcmp(name, "lock-on-console") == 0) {

View File

@@ -18,7 +18,7 @@ public:
public: public:
I18n::Message name() override; I18n::Message name() override;
I18n::Message upperName() override; I18n::Message upperName() override;
int examinationLevel() override; App::Descriptor::ExaminationLevel examinationLevel() override;
const Image * icon() override; const Image * icon() override;
}; };
class Snapshot : public ::App::Snapshot { class Snapshot : public ::App::Snapshot {
@@ -51,6 +51,7 @@ public:
} }
StackViewController * stackViewController() { return &m_codeStackViewController; } StackViewController * stackViewController() { return &m_codeStackViewController; }
ConsoleController * consoleController() { return &m_consoleController; } ConsoleController * consoleController() { return &m_consoleController; }
MenuController * menuController() { return &m_menuController; }
/* Responder */ /* Responder */
bool handleEvent(Ion::Events::Event event) override; bool handleEvent(Ion::Events::Event event) override;

View File

@@ -1,9 +1,15 @@
Console = "Interaktive Konsole"
AddScript = "Skript hinzufügen" AddScript = "Skript hinzufügen"
ScriptOptions = "Skriptoptionen" AllowedCharactersaz09 = "Erlaubte Zeichen: a-z, 0-9, _"
ExecuteScript = "Skript ausführen" Autocomplete = "Autovervollständigung"
AutoImportScript = "Automatischer Import in Konsole" AutoImportScript = "Automatischer Import in Konsole"
BuiltinsAndKeywords = "Native Funktionen und Schlüsselwörter"
Console = "Interaktive Konsole"
DeleteScript = "Skript löschen" DeleteScript = "Skript löschen"
DuplicateScript = "Skript duplizieren" DuplicateScript = "Skript duplizieren"
ExecuteScript = "Skript ausführen"
FunctionsAndVariables = "Funktionen und Variablen" FunctionsAndVariables = "Funktionen und Variablen"
AllowedCharactersaz09 = "Erlaubte Zeichen: a-z, 0-9, _" ImportedModulesAndScripts = "Importierte Module und Skripte"
NoWordAvailableHere = "Kein Wort ist hier verfübar."
ScriptInProgress = "Aktuelle Skript"
ScriptOptions = "Skriptoptionen"
ScriptSize = "Script size"

View File

@@ -1,9 +1,15 @@
Console = "Python shell"
AddScript = "Add a script" AddScript = "Add a script"
ScriptOptions = "Script options" AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _"
ExecuteScript = "Execute script" Autocomplete = "Autocomplete"
AutoImportScript = "Auto import in shell" AutoImportScript = "Auto import in shell"
BuiltinsAndKeywords = "Builtins and keywords"
Console = "Python shell"
DeleteScript = "Delete script" DeleteScript = "Delete script"
DuplicateScript = "Duplicate script" DuplicateScript = "Duplicate script"
ExecuteScript = "Execute script"
FunctionsAndVariables = "Functions and variables" FunctionsAndVariables = "Functions and variables"
AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _" ImportedModulesAndScripts = "Imported modules and scripts"
NoWordAvailableHere = "No word available here."
ScriptInProgress = "Script in progress"
ScriptOptions = "Script options"
ScriptSize = "Script size"

View File

@@ -1,9 +1,15 @@
Console = "Interprete de comandos"
AddScript = "Agregar un archivo" AddScript = "Agregar un archivo"
ScriptOptions = "Opciones del archivo" AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _"
ExecuteScript = "Ejecutar el archivo" Autocomplete = "Autocompleción"
AutoImportScript = "Importación auto en intérprete" AutoImportScript = "Importación auto en intérprete"
BuiltinsAndKeywords = "Funciones nativas y palabras clave"
Console = "Interprete de comandos"
DeleteScript = "Eliminar el archivo" DeleteScript = "Eliminar el archivo"
DuplicateScript = "Duplicar el guión" DuplicateScript = "Duplicar el guión"
ExecuteScript = "Ejecutar el archivo"
FunctionsAndVariables = "Funciones y variables" FunctionsAndVariables = "Funciones y variables"
AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _" ImportedModulesAndScripts = "Módulos y archivos importados"
NoWordAvailableHere = "No hay ninguna palabra disponible aquí."
ScriptInProgress = "Archivo en curso"
ScriptOptions = "Opciones del archivo"
ScriptSize = "Script size"

View File

@@ -1,9 +1,15 @@
Console = "Console d'exécution"
AddScript = "Ajouter un script" AddScript = "Ajouter un script"
ScriptOptions = "Options de script" AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _"
ExecuteScript = "Exécuter le script" Autocomplete = "Auto-complétion"
AutoImportScript = "Importation auto dans la console" AutoImportScript = "Importation auto dans la console"
BuiltinsAndKeywords = "Fonctions natives et mots-clés"
Console = "Console d'exécution"
DeleteScript = "Supprimer le script" DeleteScript = "Supprimer le script"
DuplicateScript = "Dupliquer le script" DuplicateScript = "Dupliquer le script"
ExecuteScript = "Exécuter le script"
FunctionsAndVariables = "Fonctions et variables" FunctionsAndVariables = "Fonctions et variables"
AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _" ImportedModulesAndScripts = "Modules et scripts importés"
NoWordAvailableHere = "Aucun mot disponible à cet endroit."
ScriptInProgress = "Script en cours"
ScriptOptions = "Options de script"
ScriptSize = "Script size"

View File

@@ -1,9 +1,15 @@
Console = "Konzol"
AddScript = "Script hozzadáadása" AddScript = "Script hozzadáadása"
ScriptOptions = "Script beállítások" AllowedCharactersaz09 = "Engedélyezett karakterek: a-z, 0-9, _"
ExecuteScript = "Script indítása" Autocomplete = "Autocomplete"
AutoImportScript = "Script automata importálása" AutoImportScript = "Script automata importálása"
BuiltinsAndKeywords = "Builtins and keywords"
Console = "Konzol"
DeleteScript = "Script törlése" DeleteScript = "Script törlése"
DuplicateScript = "Script másolása" DuplicateScript = "Script másolása"
ExecuteScript = "Script indítása"
FunctionsAndVariables = "Függvények és változók" FunctionsAndVariables = "Függvények és változók"
AllowedCharactersaz09 = "Engedélyezett karakterek: a-z, 0-9, _" ImportedModulesAndScripts = "Imported modules and scripts"
NoWordAvailableHere = "No word available here."
ScriptInProgress = "Script in progress"
ScriptOptions = "Script beállítások"
ScriptSize = "Script size"

15
apps/code/base.it.i18n Normal file
View File

@@ -0,0 +1,15 @@
AddScript = "Aggiungere script"
AllowedCharactersaz09 = "Caratteri consentiti : a-z, 0-9, _"
Autocomplete = "Autocompletamento"
AutoImportScript = "Importazione automatica dello script"
BuiltinsAndKeywords = "Funzioni native e parole chiave"
Console = "Console d'esecuzione"
DeleteScript = "Eliminare lo script"
DuplicateScript = "Duplicate script"
ExecuteScript = "Eseguire lo script"
FunctionsAndVariables = "Funzioni e variabili"
ImportedModulesAndScripts = "Moduli e scripts importati"
NoWordAvailableHere = "Nessuna parola disponibile qui."
ScriptInProgress = "Script in corso"
ScriptOptions = "Opzioni dello script"
ScriptSize = "Script Size"

15
apps/code/base.nl.i18n Normal file
View File

@@ -0,0 +1,15 @@
AddScript = "Script toevoegen"
AllowedCharactersaz09 = "Toegestane tekens: a-z, 0-9, _"
Autocomplete = "Autocomplete"
AutoImportScript = "Automatisch importeren in shell"
BuiltinsAndKeywords = "Builtins and keywords"
Console = "Python shell"
DeleteScript = "Script verwijderen"
DuplicateScript = "Duplicate script"
ExecuteScript = "Script uitvoeren"
FunctionsAndVariables = "Functies en variabelen"
ImportedModulesAndScripts = "Imported modules and scripts"
NoWordAvailableHere = "No word available here."
ScriptInProgress = "Script in progress"
ScriptOptions = "Script opties"
ScriptSize = "Script Size"

View File

@@ -1,9 +1,15 @@
Console = "Interpretador interativo"
AddScript = "Adicionar um script" AddScript = "Adicionar um script"
ScriptOptions = "Opções de script" AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _"
ExecuteScript = "Executar o script" Autocomplete = "Preenchimento automático"
AutoImportScript = "Importação auto no interpretador" AutoImportScript = "Importação auto no interpretador"
BuiltinsAndKeywords = "Funções nativas e palavras-chave"
Console = "Interpretador interativo"
DeleteScript = "Eliminar o script" DeleteScript = "Eliminar o script"
DuplicateScript = "Duplicar o script" DuplicateScript = "Duplicar o script"
ExecuteScript = "Executar o script"
FunctionsAndVariables = "Funções e variáveis" FunctionsAndVariables = "Funções e variáveis"
AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _" ImportedModulesAndScripts = "Módulos e scripts importados"
NoWordAvailableHere = "Nenhuma palavra disponível aqui."
ScriptInProgress = "Script em curso"
ScriptOptions = "Opções de script"
ScriptSize = "Script Size"

View File

@@ -26,7 +26,18 @@ PythonCeil = "Aufrundung"
PythonChoice = "Zufallszahl aus der Liste" PythonChoice = "Zufallszahl aus der Liste"
PythonClear = "Leere die Liste" PythonClear = "Leere die Liste"
PythonCmathFunction = "cmath-Modul-Funktionspräfix" PythonCmathFunction = "cmath-Modul-Funktionspräfix"
PythonColor = "Definiert eine RGB-Farbe" PythonColor = "Definiere eine RGB-Farbe"
PythonColorBlack = "Black color"
PythonColorBlue = "Blue color"
PythonColorBrown = "Brown color"
PythonColorGreen = "Green color"
PythonColorGrey = "Grey color"
PythonColorOrange = "Orange color"
PythonColorPink = "Pink color"
PythonColorPurple = "Purple color"
PythonColorRed = "Red color"
PythonColorWhite = "White color"
PythonColorYellow = "Yellow color"
PythonComplex = "a+ib zurückgeben" PythonComplex = "a+ib zurückgeben"
PythonCopySign = "x mit dem Vorzeichen von y" PythonCopySign = "x mit dem Vorzeichen von y"
PythonCos = "Kosinus" PythonCos = "Kosinus"
@@ -45,10 +56,10 @@ PythonFillRect = "Malt ein Rechteck bei Pixel (x,y)"
PythonFloat = "Wandelt x zu float um" PythonFloat = "Wandelt x zu float um"
PythonFloor = "Floor" PythonFloor = "Floor"
PythonFmod = "a modulo b" PythonFmod = "a modulo b"
PythonFrExp = "Rest und Exponent von x" PythonFrExp = "Mantissa and exponent of x: (m,e)"
PythonGamma = "Gammafunktion" PythonGamma = "Gamma function"
PythonGetPixel = "Farbe von Pixel (x,y)" PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Ganzzahl mit k zufälligen Bits" PythonGetrandbits = "Integer with k random bits"
PythonGrid = "Toggle the visibility of the grid" PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Ganzzahl zu Hexadecimal" PythonHex = "Ganzzahl zu Hexadecimal"
PythonHist = "Draw the histogram of x" PythonHist = "Draw the histogram of x"
@@ -139,10 +150,10 @@ PythonRadians = "Convert x from degrees to radians"
PythonRandint = "Random integer in [a,b]" PythonRandint = "Random integer in [a,b]"
PythonRandom = "Floating point number in [0,1[" PythonRandom = "Floating point number in [0,1["
PythonRandomFunction = "random module function prefix" PythonRandomFunction = "random module function prefix"
PythonRandrange = "Random number in range(start, stop)" PythonRandrange = "Random number in range(start,stop)"
PythonRangeStartStop = "List from start to stop-1" PythonRangeStartStop = "List from start to stop-1"
PythonRangeStop = "List from 0 to stop-1" PythonRangeStop = "List from 0 to stop-1"
PythonRect = "z in cartesian coordinates" PythonRect = "Convert to cartesian coordinates"
PythonRemove = "Remove the first occurrence of x" PythonRemove = "Remove the first occurrence of x"
PythonReverse = "Reverse the elements of the list" PythonReverse = "Reverse the elements of the list"
PythonRound = "Round to n digits" PythonRound = "Round to n digits"
@@ -162,39 +173,45 @@ PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module function prefix" PythonTimeFunction = "time module function prefix"
PythonTrunc = "x truncated to an integer" PythonTrunc = "x truncated to an integer"
PythonTurtleBackward = "Move backward by x pixels" PythonTurtleBackward = "Move backward by x pixels"
PythonTurtleBlack = "Schwarze Farbe"
PythonTurtleBlue = "Blaue Farbe"
PythonTurtleBrown = "Braune Farbe"
PythonTurtleCircle = "Circle of radius r pixels" PythonTurtleCircle = "Circle of radius r pixels"
PythonTurtleColor = "Stiftfarbe setzen" PythonTurtleColor = "Stiftfarbe setzen"
PythonTurtleColorMode = "Set the color mode to 1.0 or 255"
PythonTurtleForward = "Move forward by x pixels" PythonTurtleForward = "Move forward by x pixels"
PythonTurtleFunction = "turtle module function prefix" PythonTurtleFunction = "turtle module function prefix"
PythonTurtleGoto = "Move to (x,y) coordinates" PythonTurtleGoto = "Move to (x,y) coordinates"
PythonTurtleGreen = "Grüne Farbe"
PythonTurtleGrey = "Graue Farbe"
PythonTurtleHeading = "Return the current heading" PythonTurtleHeading = "Return the current heading"
PythonTurtleHideturtle = "Hide the turtle" PythonTurtleHideturtle = "Hide the turtle"
PythonTurtleIsdown = "Return True if the pen is down" PythonTurtleIsdown = "Return True if the pen is down"
PythonTurtleLeft = "Turn left by a degrees" PythonTurtleLeft = "Turn left by a degrees"
PythonTurtleOrange = "Orange color"
PythonTurtlePendown = "Pull the pen down" PythonTurtlePendown = "Pull the pen down"
PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtlePensize = "Set the line thickness to x pixels"
PythonTurtlePenup = "Pull the pen up" PythonTurtlePenup = "Pull the pen up"
PythonTurtlePink = "Pinke Farbe"
PythonTurtlePosition = "Return the current (x,y) location" PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtlePurple = "Purple color"
PythonTurtleRed = "Rote Farbe"
PythonTurtleReset = "Reset the drawing" PythonTurtleReset = "Reset the drawing"
PythonTurtleRight = "Turn right by a degrees" PythonTurtleRight = "Turn right by a degrees"
PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetheading = "Set the orientation to a degrees"
PythonTurtleSetposition = "Position des turtles" PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Die turtle anzeigen" PythonTurtleShowturtle = "Show the turtle"
PythonTurtleSpeed = "Zeichengeschwindigkeit zwischen 0 und 10" PythonTurtleSpeed = "Drawing speed between 0 and 10"
PythonTurtleWhite = "Weiße Farbe" PythonTurtleWrite = "Display a text"
PythonTurtleYellow = "Gelbe Farbe" PythonUniform = "Floating point number in [a,b]"
PythonUniform = "Fließkommazahl in [a,b]" PythonImportTime = "Import time module"
PythonTimeFromImport = "Import time module"
PythonTimeImport = "Import time module"
PythonTimePrefix = "time module function prefix" PythonTimePrefix = "time module function prefix"
PythonTimeSleep = "Warten Sie n Sekunden lang" PythonTimeSleep = "Wait for n second"
PythonTimeMonotonic = "Monotone Zeit zurückgeben" PythonMonotonic = "Return monotonic time"
PythonFileOpen = "Öffnet eine Datei"
PythonFileSeekable = "Ist eine Datei durchsuchbar?"
PythonFileSeek = "Dateicursor verschieben"
PythonFileTell = "Cursorposition der Datei abrufen"
PythonFileClose = "Schließt eine Datei"
PythonFileClosed = "Wenn Datei geschlossen wurde"
PythonFileRead = "Bis zu size Bytes lesen"
PythonFileWrite = "Schreibe b in die Datei"
PythonFileReadline = "Lies eine Zeile"
PythonFileReadlines = "Liest eine Liste von Zeilen"
PythonFileTruncate = "Größe der Datei ändern"
PythonFileWritelines = "Schreibt eine Liste von Zeilen"
PythonFileName = "Dateiname"
PythonFileMode = "Dateiöffnungsmodus"
PythonFileReadable = "Ist die Datei lesbar?"
PythonFileWritable = "Ist die Datei beschreibbar?"

View File

@@ -1,7 +1,7 @@
PythonPound = "Comment" PythonPound = "Comment"
PythonPercent = "Modulo" PythonPercent = "Modulo"
Python1J = "Imaginary i" Python1J = "Imaginary i"
PythonLF = "Line feed" PythonLF = "line feed"
PythonTab = "Tabulation" PythonTab = "Tabulation"
PythonAmpersand = "Bitwise and" PythonAmpersand = "Bitwise and"
PythonSymbolExp = "Bitwise exclusive or" PythonSymbolExp = "Bitwise exclusive or"
@@ -27,6 +27,17 @@ PythonChoice = "Random number in the list"
PythonClear = "Empty the list" PythonClear = "Empty the list"
PythonCmathFunction = "cmath module function prefix" PythonCmathFunction = "cmath module function prefix"
PythonColor = "Define a rgb color" PythonColor = "Define a rgb color"
PythonColorBlack = "Black color"
PythonColorBlue = "Blue color"
PythonColorBrown = "Brown color"
PythonColorGreen = "Green color"
PythonColorGrey = "Grey color"
PythonColorOrange = "Orange color"
PythonColorPink = "Pink color"
PythonColorPurple = "Purple color"
PythonColorRed = "Red color"
PythonColorWhite = "White color"
PythonColorYellow = "Yellow color"
PythonComplex = "Return a+ib" PythonComplex = "Return a+ib"
PythonCopySign = "Return x with the sign of y" PythonCopySign = "Return x with the sign of y"
PythonCos = "Cosine" PythonCos = "Cosine"
@@ -45,7 +56,7 @@ PythonFillRect = "Fill a rectangle at pixel (x,y)"
PythonFloat = "Convert x to a float" PythonFloat = "Convert x to a float"
PythonFloor = "Floor" PythonFloor = "Floor"
PythonFmod = "a modulo b" PythonFmod = "a modulo b"
PythonFrExp = "Mantissa and exponent of x" PythonFrExp = "Mantissa and exponent of x: (m,e)"
PythonGamma = "Gamma function" PythonGamma = "Gamma function"
PythonGetPixel = "Return pixel (x,y) color" PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits" PythonGetrandbits = "Integer with k random bits"
@@ -139,10 +150,10 @@ PythonRadians = "Convert x from degrees to radians"
PythonRandint = "Random integer in [a,b]" PythonRandint = "Random integer in [a,b]"
PythonRandom = "Floating point number in [0,1[" PythonRandom = "Floating point number in [0,1["
PythonRandomFunction = "random module function prefix" PythonRandomFunction = "random module function prefix"
PythonRandrange = "Random number in range(start, stop)" PythonRandrange = "Random number in range(start,stop)"
PythonRangeStartStop = "List from start to stop-1" PythonRangeStartStop = "List from start to stop-1"
PythonRangeStop = "List from 0 to stop-1" PythonRangeStop = "List from 0 to stop-1"
PythonRect = "z in cartesian coordinates" PythonRect = "Convert to cartesian coordinates"
PythonRemove = "Remove the first occurrence of x" PythonRemove = "Remove the first occurrence of x"
PythonReverse = "Reverse the elements of the list" PythonReverse = "Reverse the elements of the list"
PythonRound = "Round to n digits" PythonRound = "Round to n digits"
@@ -162,39 +173,45 @@ PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module function prefix" PythonTimeFunction = "time module function prefix"
PythonTrunc = "x truncated to an integer" PythonTrunc = "x truncated to an integer"
PythonTurtleBackward = "Move backward by x pixels" PythonTurtleBackward = "Move backward by x pixels"
PythonTurtleBlack = "Black color"
PythonTurtleBlue = "Blue color"
PythonTurtleBrown = "Brown color"
PythonTurtleCircle = "Circle of radius r pixels" PythonTurtleCircle = "Circle of radius r pixels"
PythonTurtleColor = "Set the pen color" PythonTurtleColor = "Set the pen color"
PythonTurtleColorMode = "Set the color mode to 1.0 or 255"
PythonTurtleForward = "Move forward by x pixels" PythonTurtleForward = "Move forward by x pixels"
PythonTurtleFunction = "turtle module function prefix" PythonTurtleFunction = "turtle module function prefix"
PythonTurtleGoto = "Move to (x,y) coordinates" PythonTurtleGoto = "Move to (x,y) coordinates"
PythonTurtleGreen = "Green color"
PythonTurtleGrey = "Grey color"
PythonTurtleHeading = "Return the current heading" PythonTurtleHeading = "Return the current heading"
PythonTurtleHideturtle = "Hide the turtle" PythonTurtleHideturtle = "Hide the turtle"
PythonTurtleIsdown = "Return True if the pen is down" PythonTurtleIsdown = "Return True if the pen is down"
PythonTurtleLeft = "Turn left by a degrees" PythonTurtleLeft = "Turn left by a degrees"
PythonTurtleOrange = "Orange color"
PythonTurtlePendown = "Pull the pen down" PythonTurtlePendown = "Pull the pen down"
PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtlePensize = "Set the line thickness to x pixels"
PythonTurtlePenup = "Pull the pen up" PythonTurtlePenup = "Pull the pen up"
PythonTurtlePink = "Pink color"
PythonTurtlePosition = "Return the current (x,y) location" PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtlePurple = "Purple color"
PythonTurtleRed = "Red color"
PythonTurtleReset = "Reset the drawing" PythonTurtleReset = "Reset the drawing"
PythonTurtleRight = "Turn right by a degrees" PythonTurtleRight = "Turn right by a degrees"
PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetheading = "Set the orientation to a degrees"
PythonTurtleSetposition = "Positionne la tortue" PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Show the turtle" PythonTurtleShowturtle = "Show the turtle"
PythonTurtleSpeed = "Drawing speed between 0 and 10" PythonTurtleSpeed = "Drawing speed between 0 and 10"
PythonTurtleWhite = "White color" PythonTurtleWrite = "Display a text"
PythonTurtleYellow = "Yellow color"
PythonUniform = "Floating point number in [a,b]" PythonUniform = "Floating point number in [a,b]"
PythonTimeFromImport = "Import time module" PythonImportTime = "Import time module"
PythonTimeImport = "Import time module"
PythonTimePrefix = "time module function prefix" PythonTimePrefix = "time module function prefix"
PythonTimeSleep = "Wait for n second" PythonTimeSleep = "Wait for n second"
PythonTimeMonotonic = "Return monotonic time" 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"

View File

@@ -27,6 +27,17 @@ PythonChoice = "Random number in the list"
PythonClear = "Empty the list" PythonClear = "Empty the list"
PythonCmathFunction = "cmath module function prefix" PythonCmathFunction = "cmath module function prefix"
PythonColor = "Define a rgb color" PythonColor = "Define a rgb color"
PythonColorBlack = "Black color"
PythonColorBlue = "Blue color"
PythonColorBrown = "Brown color"
PythonColorGreen = "Green color"
PythonColorGrey = "Grey color"
PythonColorOrange = "Orange color"
PythonColorPink = "Pink color"
PythonColorPurple = "Purple color"
PythonColorRed = "Red color"
PythonColorWhite = "White color"
PythonColorYellow = "Yellow color"
PythonComplex = "Return a+ib" PythonComplex = "Return a+ib"
PythonCopySign = "Return x with the sign of y" PythonCopySign = "Return x with the sign of y"
PythonCos = "Cosine" PythonCos = "Cosine"
@@ -45,7 +56,7 @@ PythonFillRect = "Fill a rectangle at pixel (x,y)"
PythonFloat = "Convert x to a float" PythonFloat = "Convert x to a float"
PythonFloor = "Floor" PythonFloor = "Floor"
PythonFmod = "a modulo b" PythonFmod = "a modulo b"
PythonFrExp = "Mantissa and exponent of x" PythonFrExp = "Mantissa and exponent of x: (m,e)"
PythonGamma = "Gamma function" PythonGamma = "Gamma function"
PythonGetPixel = "Return pixel (x,y) color" PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits" PythonGetrandbits = "Integer with k random bits"
@@ -139,10 +150,10 @@ PythonRadians = "Convert x from degrees to radians"
PythonRandint = "Random integer in [a,b]" PythonRandint = "Random integer in [a,b]"
PythonRandom = "Floating point number in [0,1[" PythonRandom = "Floating point number in [0,1["
PythonRandomFunction = "random module function prefix" PythonRandomFunction = "random module function prefix"
PythonRandrange = "Random number in range(start, stop)" PythonRandrange = "Random number in range(start,stop)"
PythonRangeStartStop = "List from start to stop-1" PythonRangeStartStop = "List from start to stop-1"
PythonRangeStop = "List from 0 to stop-1" PythonRangeStop = "List from 0 to stop-1"
PythonRect = "z in cartesian coordinates" PythonRect = "Convert to cartesian coordinates"
PythonRemove = "Remove the first occurrence of x" PythonRemove = "Remove the first occurrence of x"
PythonReverse = "Reverse the elements of the list" PythonReverse = "Reverse the elements of the list"
PythonRound = "Round to n digits" PythonRound = "Round to n digits"
@@ -162,39 +173,45 @@ PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module function prefix" PythonTimeFunction = "time module function prefix"
PythonTrunc = "x truncated to an integer" PythonTrunc = "x truncated to an integer"
PythonTurtleBackward = "Move backward by x pixels" PythonTurtleBackward = "Move backward by x pixels"
PythonTurtleBlack = "Black color"
PythonTurtleBlue = "Blue color"
PythonTurtleBrown = "Brown color"
PythonTurtleCircle = "Circle of radius r pixels" PythonTurtleCircle = "Circle of radius r pixels"
PythonTurtleColor = "Set the pen color" PythonTurtleColor = "Set the pen color"
PythonTurtleColorMode = "Set the color mode to 1.0 or 255"
PythonTurtleForward = "Move forward by x pixels" PythonTurtleForward = "Move forward by x pixels"
PythonTurtleFunction = "turtle module function prefix" PythonTurtleFunction = "turtle module function prefix"
PythonTurtleGoto = "Move to (x,y) coordinates" PythonTurtleGoto = "Move to (x,y) coordinates"
PythonTurtleGreen = "Green color"
PythonTurtleGrey = "Grey color"
PythonTurtleHeading = "Return the current heading" PythonTurtleHeading = "Return the current heading"
PythonTurtleHideturtle = "Hide the turtle" PythonTurtleHideturtle = "Hide the turtle"
PythonTurtleIsdown = "Return True if the pen is down" PythonTurtleIsdown = "Return True if the pen is down"
PythonTurtleLeft = "Turn left by a degrees" PythonTurtleLeft = "Turn left by a degrees"
PythonTurtleOrange = "Orange color"
PythonTurtlePendown = "Pull the pen down" PythonTurtlePendown = "Pull the pen down"
PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtlePensize = "Set the line thickness to x pixels"
PythonTurtlePenup = "Pull the pen up" PythonTurtlePenup = "Pull the pen up"
PythonTurtlePink = "Pink color"
PythonTurtlePosition = "Return the current (x,y) location" PythonTurtlePosition = "Return the current (x,y) location"
PythonTurtlePurple = "Purple color"
PythonTurtleRed = "Red color"
PythonTurtleReset = "Reset the drawing" PythonTurtleReset = "Reset the drawing"
PythonTurtleRight = "Turn right by a degrees" PythonTurtleRight = "Turn right by a degrees"
PythonTurtleSetheading = "Set the orientation to a degrees" PythonTurtleSetheading = "Set the orientation to a degrees"
PythonTurtleSetposition = "Positionne la tortue" PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Show the turtle" PythonTurtleShowturtle = "Show the turtle"
PythonTurtleSpeed = "Drawing speed between 0 and 10" PythonTurtleSpeed = "Drawing speed between 0 and 10"
PythonTurtleWhite = "White color" PythonTurtleWrite = "Display a text"
PythonTurtleYellow = "Yellow color"
PythonUniform = "Floating point number in [a,b]" PythonUniform = "Floating point number in [a,b]"
PythonTimeFromImport = "Import time module" PythonImportTime = "Import time module"
PythonTimeImport = "Import time module"
PythonTimePrefix = "time module function prefix" PythonTimePrefix = "time module function prefix"
PythonTimeSleep = "Esperar n segundos" PythonTimeSleep = "Esperar n segundos"
PythonTimeMonotonic = "Tiempo monótono de retorno" PythonMonotonic = "Tiempo monótono de retorno"
PythonFileOpen = "Opens a file"
PythonFileSeekable = "Tells if seek can be used on a file"
PythonFileSeek = "Move file's internal cursor"
PythonFileTell = "Get file's internal 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"

View File

@@ -27,6 +27,17 @@ PythonChoice = "Nombre aléatoire dans la liste"
PythonClear = "Vide la liste" PythonClear = "Vide la liste"
PythonCmathFunction = "Préfixe fonction du module cmath" PythonCmathFunction = "Préfixe fonction du module cmath"
PythonColor = "Définit une couleur rvb" PythonColor = "Définit une couleur rvb"
PythonColorBlack = "Couleur noire"
PythonColorBlue = "Couleur bleue"
PythonColorBrown = "Couleur marron"
PythonColorGreen = "Couleur verte"
PythonColorGrey = "Couleur grise"
PythonColorOrange = "Couleur orange"
PythonColorPink = "Couleur rose"
PythonColorPurple = "Couleur violette"
PythonColorRed = "Couleur rouge"
PythonColorWhite = "Couleur blanche"
PythonColorYellow = "Couleur jaune"
PythonComplex = "Renvoie a+ib" PythonComplex = "Renvoie a+ib"
PythonCopySign = "Renvoie x avec le signe de y" PythonCopySign = "Renvoie x avec le signe de y"
PythonCos = "Cosinus" PythonCos = "Cosinus"
@@ -139,7 +150,7 @@ PythonRadians = "Conversion de degrés en radians"
PythonRandint = "Entier aléatoire dans [a,b]" PythonRandint = "Entier aléatoire dans [a,b]"
PythonRandom = "Nombre décimal dans [0,1[" PythonRandom = "Nombre décimal dans [0,1["
PythonRandomFunction = "Préfixe fonction du module random" PythonRandomFunction = "Préfixe fonction du module random"
PythonRandrange = "Nombre dans range(start, stop)" PythonRandrange = "Nombre dans range(start,stop)"
PythonRangeStartStop = "Liste de start à stop-1" PythonRangeStartStop = "Liste de start à stop-1"
PythonRangeStop = "Liste de 0 à stop-1" PythonRangeStop = "Liste de 0 à stop-1"
PythonRect = "Conversion en algébrique" PythonRect = "Conversion en algébrique"
@@ -162,39 +173,45 @@ PythonText = "Affiche un texte en (x,y)"
PythonTimeFunction = "Préfixe fonction module time" PythonTimeFunction = "Préfixe fonction module time"
PythonTrunc = "Troncature entière" PythonTrunc = "Troncature entière"
PythonTurtleBackward = "Recule de x pixels" PythonTurtleBackward = "Recule de x pixels"
PythonTurtleBlack = "Couleur noire"
PythonTurtleBlue = "Couleur bleue"
PythonTurtleBrown = "Couleur marron"
PythonTurtleCircle = "Cercle de rayon r pixels" PythonTurtleCircle = "Cercle de rayon r pixels"
PythonTurtleColor = "Modifie la couleur du tracé" PythonTurtleColor = "Modifie la couleur du tracé"
PythonTurtleColorMode = "Met le mode de couleur à 1.0 ou 255"
PythonTurtleForward = "Avance de x pixels" PythonTurtleForward = "Avance de x pixels"
PythonTurtleFunction = "Préfixe fonction du module turtle" PythonTurtleFunction = "Préfixe fonction du module turtle"
PythonTurtleGoto = "Va au point de coordonnées (x,y)" PythonTurtleGoto = "Va au point de coordonnées (x,y)"
PythonTurtleGreen = "Couleur verte"
PythonTurtleGrey = "Couleur grise"
PythonTurtleHeading = "Renvoie l'orientation actuelle" PythonTurtleHeading = "Renvoie l'orientation actuelle"
PythonTurtleHideturtle = "Masque la tortue" PythonTurtleHideturtle = "Masque la tortue"
PythonTurtleIsdown = "True si le crayon est abaissé" PythonTurtleIsdown = "True si le crayon est abaissé"
PythonTurtleLeft = "Pivote de a degrés vers la gauche" PythonTurtleLeft = "Pivote de a degrés vers la gauche"
PythonTurtleOrange = "Couleur orange"
PythonTurtlePendown = "Abaisse le crayon" PythonTurtlePendown = "Abaisse le crayon"
PythonTurtlePensize = "Taille du tracé en pixels" PythonTurtlePensize = "Taille du tracé en pixels"
PythonTurtlePenup = "Relève le crayon" PythonTurtlePenup = "Relève le crayon"
PythonTurtlePink = "Couleur rose"
PythonTurtlePosition = "Renvoie la position (x,y)" PythonTurtlePosition = "Renvoie la position (x,y)"
PythonTurtlePurple = "Couleur violette"
PythonTurtleRed = "Couleur rouge"
PythonTurtleReset = "Réinitialise le dessin" PythonTurtleReset = "Réinitialise le dessin"
PythonTurtleRight = "Pivote de a degrés vers la droite" PythonTurtleRight = "Pivote de a degrés vers la droite"
PythonTurtleSetheading = "Met un cap de a degrés" PythonTurtleSetheading = "Met un cap de a degrés"
PythonTurtleSetposition = "Positionne la tortue" PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Affiche la tortue" PythonTurtleShowturtle = "Affiche la tortue"
PythonTurtleSpeed = "Vitesse du tracé entre 0 et 10" PythonTurtleSpeed = "Vitesse du tracé entre 0 et 10"
PythonTurtleWhite = "Couleur blanche" PythonTurtleWrite = "Affiche un texte"
PythonTurtleYellow = "Couleur jaune"
PythonUniform = "Nombre décimal dans [a,b]" PythonUniform = "Nombre décimal dans [a,b]"
PythonTimeFromImport = "Importation du module temps" PythonImportTime = "Importation du module temps"
PythonTimeImport = "Importation du module temps"
PythonTimePrefix = "Préfixe fonction du module temps" PythonTimePrefix = "Préfixe fonction du module temps"
PythonTimeSleep = "Attendre n secondes" PythonTimeSleep = "Attendre n secondes"
PythonTimeMonotonic = "Retourne le temps monotonic" PythonMonotonic = "Retourne le temps monotonic"
PythonFileOpen = "Ouvre un fichier"
PythonFileSeekable = "Indique si seek peut être utilisé"
PythonFileSeek = "Déplace le curseur interne"
PythonFileTell = "Donne la posititon du curseur"
PythonFileClose = "Ferme un fichier"
PythonFileClosed = "True si le fichier a été fermé"
PythonFileRead = "Lis jusqu'à size bytes"
PythonFileWrite = "Écris b dans le fichier"
PythonFileReadline = "Lis une ligne ou jusqu'à size bytes"
PythonFileReadlines = "Lis une liste de lignes"
PythonFileTruncate = "Redimensionne le fichier"
PythonFileWritelines = "Écris une liste de lignes"
PythonFileName = "Nom du fichier"
PythonFileMode = "Mode d'ouverture du fichier"
PythonFileReadable = "Indique si read peut être utilisé"
PythonFileWritable = "Indique si write peut être utilisé"

View File

@@ -27,6 +27,17 @@ PythonChoice = "Véletlenszerü szám a listában"
PythonClear = "A lista ürítése" PythonClear = "A lista ürítése"
PythonCmathFunction = "cmath modul funkció elötag" PythonCmathFunction = "cmath modul funkció elötag"
PythonColor = "Rgb szín meghatározása" PythonColor = "Rgb szín meghatározása"
PythonColorBlack = "Fekete szín"
PythonColorBlue = "Kék szín"
PythonColorBrown = "Barna szín"
PythonColorGreen = "Zöld szín"
PythonColorGrey = "Szürke szín"
PythonColorOrange = "Narancssárga szín"
PythonColorPink = "Rózsaszín szín"
PythonColorPurple = "Lila szín"
PythonColorRed = "Piros szín"
PythonColorWhite = "White color"
PythonColorYellow = "Sárga szín"
PythonComplex = "A + ib visszaadása" PythonComplex = "A + ib visszaadása"
PythonCopySign = "Visszatérés x-val y jelével" PythonCopySign = "Visszatérés x-val y jelével"
PythonCos = "Koszinusz" PythonCos = "Koszinusz"
@@ -162,39 +173,45 @@ PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "idömodul funkció elötag" PythonTimeFunction = "idömodul funkció elötag"
PythonTrunc = "x egészre csonkítva" PythonTrunc = "x egészre csonkítva"
PythonTurtleBackward = "Visszalépés x pixelrel" PythonTurtleBackward = "Visszalépés x pixelrel"
PythonTurtleBlack = "Fekete szín"
PythonTurtleBlue = "Kék szín"
PythonTurtleBrown = "Barna szín"
PythonTurtleCircle = "r pixel sugarú kör" PythonTurtleCircle = "r pixel sugarú kör"
PythonTurtleColor = "Állítsa be az toll színét" PythonTurtleColor = "Állítsa be az toll színét"
PythonTurtleColorMode = "Set the color mode to 1.0 or 255"
PythonTurtleForward = "Ugrás x pixelrel" PythonTurtleForward = "Ugrás x pixelrel"
PythonTurtleFunction = "teknös modul funkció elötag" PythonTurtleFunction = "teknös modul funkció elötag"
PythonTurtleGoto = "Mozgatás (x, y) koordinátákra" PythonTurtleGoto = "Mozgatás (x, y) koordinátákra"
PythonTurtleGreen = "Zöld szín"
PythonTurtleGrey = "Szürke szín"
PythonTurtleHeading = "Visszaadja az aktuális címsort" PythonTurtleHeading = "Visszaadja az aktuális címsort"
PythonTurtleHideturtle = "A teknös elrejtése" PythonTurtleHideturtle = "A teknös elrejtése"
PythonTurtleIsdown = "Visszatérés igazhoz, ha az toll lefelé" PythonTurtleIsdown = "Visszatérés igazhoz, ha az toll lefelé"
PythonTurtleLeft = "Forduljon fokkal balra" PythonTurtleLeft = "Forduljon fokkal balra"
PythonTurtleOrange = "Narancssárga szín"
PythonTurtlePendown = "Húzza le a tollat" PythonTurtlePendown = "Húzza le a tollat"
PythonTurtlePensize = "Állítsa a vonalvastagságot x pixelre" PythonTurtlePensize = "Állítsa a vonalvastagságot x pixelre"
PythonTurtlePenup = "Húzza fel a tollat" PythonTurtlePenup = "Húzza fel a tollat"
PythonTurtlePink = "Rózsaszín szín"
PythonTurtlePosition = "Az aktuális (x, y) hely visszaadása" PythonTurtlePosition = "Az aktuális (x, y) hely visszaadása"
PythonTurtlePurple = "Lila szín"
PythonTurtleRed = "Piros szín"
PythonTurtleReset = "A rajz visszaállítása" PythonTurtleReset = "A rajz visszaállítása"
PythonTurtleRight = "Forduljon fokkal jobbra" PythonTurtleRight = "Forduljon fokkal jobbra"
PythonTurtleSetheading = "Állítsa be a tájolást fokokra" PythonTurtleSetheading = "Állítsa be a tájolást fokokra"
PythonTurtleSetposition = "A helymeghatározás" PythonTurtleSetposition = "A helymeghatározás"
PythonTurtleShowturtle = "Mutasd a teknösöt" PythonTurtleShowturtle = "Mutasd a teknösöt"
PythonTurtleSpeed = "Rajzolási sebesség 0 és 10 között" PythonTurtleSpeed = "Rajzolási sebesség 0 és 10 között"
PythonTurtleWhite = "Fehér szín" PythonTurtleWrite = "Display a text"
PythonTurtleYellow = "Sárga szín"
PythonUniform = "Lebegöpontos szám [a, b] -ben" PythonUniform = "Lebegöpontos szám [a, b] -ben"
PythonTimeFromImport = "Idömodul importálása" PythonImportTime = "Idömodul importálása"
PythonTimeImport = "Idömodul importálása"
PythonTimePrefix = "idömodul funkció elötag" PythonTimePrefix = "idömodul funkció elötag"
PythonTimeSleep = "Várj n másodpercet" PythonTimeSleep = "Várj n másodpercet"
PythonTimeMonotonic = "Vissza a monoton idö" PythonMonotonic = "Vissza a monoton idö"
PythonFileOpen = "Fájl megnyitása"
PythonFileSeekable = "A fájl kereshető?"
PythonFileSeek = "A fájl kurzorának áthelyezése"
PythonFileTell = "A fájl kurzorának helye"
PythonFileClose = "Bezár egy fájlt"
PythonFileClosed = "Igaz, ha a fájl bezárt"
PythonFileRead = "Olvasson méretbájtig"
PythonFileWrite = "B beírása fájlba"
PythonFileReadline = "Olvas egy sort"
PythonFileReadlines = "Olvassa a sorok listáját"
PythonFileTruncate = "A fájl átméretezése méretre"
PythonFileWritelines = "Sorok listáját írja"
PythonFileName = "a fájl neve"
PythonFileMode = "a fájl nyitott módja"
PythonFileReadable = "A fájl olvasható?"
PythonFileWritable = "A fájl írható?"

217
apps/code/catalog.it.i18n Normal file
View File

@@ -0,0 +1,217 @@
PythonPound = "Commento"
PythonPercent = "Modulo"
Python1J = "Unità immaginaria"
PythonLF = "Nuova riga"
PythonTab = "Tabulazione"
PythonAmpersand = "Congiunzione"
PythonSymbolExp = "Disgiunzione esclusiva"
PythonVerticalBar = "Disgiunzione"
PythonImag = "Parte immaginaria di z"
PythonReal = "Parte reale di z"
PythonSingleQuote = "Apostrofo"
PythonAbs = "Valore assoluto/Modulo"
PythonAcos = "Coseno d'arco"
PythonAcosh = "Coseno iperbolico inverso"
PythonAppend = "Inserisce x alla fine della lista"
PythonArrow = "Freccia da (x,y) a (x+dx,y+dy)"
PythonAsin = "Arco sinusoidale"
PythonAsinh = "Arco sinusoidale iperbolico"
PythonAtan = "Arco tangente"
PythonAtan2 = "Calcolo di atan(y/x)"
PythonAtanh = "Arco tangente iperbolico"
PythonAxis = "Imposta assi (xmin,xmax,ymin,ymax)"
PythonBar = "Grafico a barre con x valori"
PythonBin = "Converte un intero in binario"
PythonCeil = "Parte intera superiore"
PythonChoice = "Numero aleatorio nella lista"
PythonClear = "Svuota la lista"
PythonCmathFunction = "Funz. prefissata modulo cmath"
PythonColor = "Definisci un colore rvb"
PythonColorBlack = "Colore nero"
PythonColorBlue = "Colore blu"
PythonColorBrown = "Colore marrone"
PythonColorGreen = "Colore verde"
PythonColorGrey = "Colore grigio"
PythonColorOrange = "Colore arancione"
PythonColorPink = "Colore rosa"
PythonColorPurple = "Colore viola"
PythonColorRed = "Colore rosso"
PythonColorWhite = "Colore bianco"
PythonColorYellow = "Colore giallo"
PythonComplex = "Restituisce a+ib"
PythonCopySign = "Restituisce x con segno di y"
PythonCos = "Coseno"
PythonCosh = "Coseno iperbolico"
PythonCount = "Conta le ricorrenze di x"
PythonDegrees = "Conversione di radianti in gradi"
PythonDivMod = "Quoziente e resto"
PythonDrawString = "Visualizza il testo dal pixel x,y"
PythonErf = "Funzione d'errore"
PythonErfc = "Funzione d'errore complementare"
PythonEval = "Valuta l'espressione nell'argomento "
PythonExp = "Funzione esponenziale"
PythonExpm1 = "Calcola exp(x)-1"
PythonFabs = "Valore assoluto"
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"
PythonGetPixel = "Restituisce colore del pixel(x,y)"
PythonGetrandbits = "Numero aleatorio con k bit"
PythonGrid = "Attiva la visibilità della griglia"
PythonHex = "Conversione intero in esadecimale"
PythonHist = "Disegna l'istogramma di x"
PythonImportCmath = "Importa modulo cmath"
PythonImportIon = "Importa modulo ion"
PythonImportKandinsky = "Importa modulo kandinsky"
PythonImportRandom = "Importa modulo random"
PythonImportMath = "Importa modulo math"
PythonImportMatplotlibPyplot = "Importa modulo matplotlib.pyplot"
PythonImportTurtle = "Importa del modulo turtle"
PythonImportTime = "Importa del modulo time"
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"
PythonIsKeyDown = "Restituisce True premendo tasto k"
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"
PythonLog = "Logaritmo di base a"
PythonLog10 = "Logaritmo decimale"
PythonLog2 = "Logaritmo di base 2"
PythonMathFunction = "Prefisso funzione del modulo math"
PythonMatplotlibPyplotFunction = "Prefisso modulo matplotlib.pyplot"
PythonMax = "Massimo"
PythonMin = "Minimo"
PythonModf = "Parti frazionarie e intere"
PythonMonotonic = "Restituisce il valore dell'orologio"
PythonOct = "Conversione in ottale"
PythonPhase = "Argomento di z"
PythonPlot = "Disegna y in f. di x come linee"
PythonPolar = "Conversione in polare"
PythonPop = "Cancella l'ultimo elemento"
PythonPower = "x alla potenza y"
PythonPrint = "Visualizza l'oggetto"
PythonRadians = "Conversione da gradi a radianti"
PythonRandint = "Intero aleatorio in [a,b]"
PythonRandom = "Numero aleatorio in [0,1["
PythonRandomFunction = "Prefisso funzione modulo casuale"
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"
PythonReverse = "Inverte gli elementi della lista"
PythonRound = "Arrotondato a n cifre decimali"
PythonScatter = "Diagramma dispersione y in f. di x"
PythonSeed = "Inizializza il generatore random"
PythonSetPixel = "Colora il pixel (x,y)"
PythonShow = "Mostra la figura"
PythonSin = "Seno"
PythonSinh = "Seno iperbolico"
PythonSleep = "Sospende l'esecuzione t secondi"
PythonSort = "Ordina l'elenco"
PythonSqrt = "Radice quadrata"
PythonSum = "Somma degli elementi della lista"
PythonTan = "Tangente"
PythonTanh = "Tangente iperbolica"
PythonText = "Mostra un testo in (x,y)"
PythonTimeFunction = "Prefisso funzione modulo time"
PythonTrunc = "Troncamento intero"
PythonTurtleBackward = "Indietreggia di x pixels"
PythonTurtleCircle = "Cerchio di raggio r pixel"
PythonTurtleColor = "Modifica il colore del tratto"
PythonTurtleColorMode = "Imposta modalità colore a 1.0 o 255"
PythonTurtleForward = "Avanza di x pixel"
PythonTurtleFunction = "Prefisso funzione modello turtle"
PythonTurtleGoto = "Spostati alle coordinate (x,y)"
PythonTurtleHeading = "Restituisce l'orientamento attuale"
PythonTurtleHideturtle = "Nascondi la tartaruga"
PythonTurtleIsdown = "True se la penna è abbassata"
PythonTurtleLeft = "Ruota di a gradi a sinistra"
PythonTurtlePendown = "Abbassa la penna"
PythonTurtlePensize = "Dimensione del tratto in pixel"
PythonTurtlePenup = "Solleva la penna"
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"

217
apps/code/catalog.nl.i18n Normal file
View File

@@ -0,0 +1,217 @@
PythonPound = "Opmerkingen"
PythonPercent = "Modulo"
Python1J = "Imaginaire i"
PythonLF = "Nieuwe regel"
PythonTab = "Tabulatie"
PythonAmpersand = "Bitsgewijze en"
PythonSymbolExp = "Bitsgewijze exclusieve of"
PythonVerticalBar = "Bitsgewijze of"
PythonImag = "Imaginair deel van z"
PythonReal = "Reëel deel van z"
PythonSingleQuote = "Enkele aanhalingstekens"
PythonAbs = "Absolute waarde"
PythonAcos = "Arccosinus"
PythonAcosh = "Arccosinus hyperbolicus"
PythonAppend = "Voeg x toe aan het eind van je lijst"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
PythonAsin = "Arcsinus"
PythonAsinh = "Arcsinus hyperbolicus"
PythonAtan = "Arctangens"
PythonAtan2 = "Geeft atan(y/x)"
PythonAtanh = "Arctangens hyperbolicus"
PythonAxis = "Set the axes to (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values"
PythonBin = "Zet integer om in een binair getal"
PythonCeil = "Plafond"
PythonChoice = "Geeft willek. getal van de lijst"
PythonClear = "Lijst leegmaken"
PythonCmathFunction = "cmath module voorvoegsel"
PythonColor = "Definieer een rgb kleur"
PythonColorBlack = "Zwarte kleur"
PythonColorBlue = "Blauwe kleur"
PythonColorBrown = "Bruine kleur"
PythonColorGreen = "Groene kleur"
PythonColorGrey = "Grijze kleur"
PythonColorOrange = "Oranje kleur"
PythonColorPink = "Roze kleur"
PythonColorPurple = "Paarse kleur"
PythonColorRed = "Rode kleur"
PythonColorWhite = "Witte kleur"
PythonColorYellow = "Gele kleur"
PythonComplex = "Geeft a+ib"
PythonCopySign = "Geeft x met het teken van y"
PythonCos = "Cosinus"
PythonCosh = "Cosinus hyperbolicus"
PythonCount = "Tel voorkomen van x"
PythonDegrees = "Zet x om van radialen naar graden"
PythonDivMod = "Quotiënt en rest"
PythonDrawString = "Geef een tekst weer van pixel (x,y)"
PythonErf = "Error functie"
PythonErfc = "Complementaire error functie"
PythonEval = "Geef de geëvalueerde uitdrukking"
PythonExp = "Exponentiële functie"
PythonExpm1 = "Bereken exp(x)-1"
PythonFabs = "Absolute waarde"
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"
PythonGetPixel = "Geef pixel (x,y) kleur (rgb)"
PythonGetrandbits = "Integer met k willekeurige bits"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Zet integer om in hexadecimaal"
PythonHist = "Draw the histogram of x"
PythonImportCmath = "Importeer cmath module"
PythonImportIon = "Importeer ion module"
PythonImportKandinsky = "Importeer kandinsky module"
PythonImportRandom = "Importeer random module"
PythonImportMath = "Importeer math module"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
PythonImportTime = "Importeer time module"
PythonImportTurtle = "Importeer turtle module"
PythonIndex = "Index van de eerste x aanwezigheden"
PythonInput = "Wijs een waarde toe"
PythonInsert = "Voeg x toe aan index i in de lijst"
PythonInt = "Zet x om in een integer"
PythonIonFunction = "ion module voorvoegsel"
PythonIsFinite = "Controleer of x eindig is"
PythonIsInfinite = "Controleer of x oneindig is"
PythonIsKeyDown = "Geef True als k toets omlaag is"
PythonIsNaN = "Controleer of x geen nummer 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"
PythonLog = "Logaritme met grondgetal a"
PythonLog10 = "Logaritme met grondgetal 10"
PythonLog2 = "Logaritme met grondgetal 2"
PythonMathFunction = "math module voorvoegsel"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractionele en gehele delen van x"
PythonMonotonic = "Waarde van een monotone klok"
PythonOct = "Integer omzetten naar octaal"
PythonPhase = "Fase van z in radialen"
PythonPlot = "Plot y versus x as lines"
PythonPolar = "z in poolcoördinaten"
PythonPop = "Verwijder en breng het laatste item terug"
PythonPower = "x tot de macht y"
PythonPrint = "Print object"
PythonRadians = "Zet x om van graden naar radialen"
PythonRandint = "Geeft willek. integer in [a,b]"
PythonRandom = "Een willekeurig getal in [0,1["
PythonRandomFunction = "random module voorvoegsel"
PythonRandrange = "Willek. getal in range(start, stop)"
PythonRangeStartStop = "Lijst van start tot stop-1"
PythonRangeStop = "Lijst van 0 tot stop-1"
PythonRect = "z in cartesiaanse coördinaten"
PythonRemove = "Verwijder het eerste voorkomen van x"
PythonReverse = "Keer de elementen van de lijst om"
PythonRound = "Rond af op n cijfers"
PythonScatter = "Draw a scatter plot of y versus x"
PythonSeed = "Start willek. getallengenerator"
PythonSetPixel = "Kleur pixel (x,y)"
PythonShow = "Display the figure"
PythonSin= "Sinus"
PythonSinh = "Sinus hyperbolicus"
PythonSleep = "Stel executie voor t seconden uit"
PythonSort = "Sorteer de lijst"
PythonSqrt = "Vierkantswortel"
PythonSum = "Sommeer de items van een lijst"
PythonTan = "Tangens"
PythonTanh = "Tangens hyperbolicus"
PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module voorvoegsel"
PythonTrunc = "x afgeknot tot een integer"
PythonTurtleBackward = "Ga achterwaarts met x pixels"
PythonTurtleCircle = "Cirkel van straal r pixels"
PythonTurtleColor = "Stel de kleur van de pen in"
PythonTurtleColorMode = "Stel de kleurmodus in op 1.0 of 255"
PythonTurtleForward = "Ga voorwaarts met x pixels"
PythonTurtleFunction = "turtle module voorvoegsel"
PythonTurtleGoto = "Verplaats naar (x,y) coordinaten"
PythonTurtleHeading = "Ga terug naar de huidige koers"
PythonTurtleHideturtle = "Verberg de schildpad"
PythonTurtleIsdown = "Geeft True als pen naar beneden is"
PythonTurtleLeft = "Ga linksaf met a graden"
PythonTurtlePendown = "Zet de pen naar beneden"
PythonTurtlePensize = "Stel de lijndikte in op x pixels"
PythonTurtlePenup = "Zet de pen omhoog"
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 = "Zwevendekommagetal 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"
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"

View File

@@ -1,200 +1,217 @@
PythonPound = "Comment" PythonPound = "Comentário"
PythonPercent = "Modulo" PythonPercent = "Módulo"
Python1J = "Imaginary i" Python1J = "i Complexo"
PythonLF = "Line feed" PythonLF = "Nova linha"
PythonTab = "Tabulation" PythonTab = "Tabulação"
PythonAmpersand = "Bitwise and" PythonAmpersand = "Operador binário and"
PythonSymbolExp = "Bitwise exclusive or" PythonSymbolExp = "Operador binário exclusivo or"
PythonVerticalBar = "Bitwise or" PythonVerticalBar = "Operador binário or"
PythonSingleQuote = "Single quote" PythonSingleQuote = "Apóstrofo"
PythonImag = "Imaginary part of z" PythonImag = "Parte imaginária de z"
PythonReal = "Real part of z" PythonReal = "Parte real de z"
PythonAbs = "Absolute value/Magnitude" PythonAbs = "Valor absoluto/módulo"
PythonAcos = "Arc cosine" PythonAcos = "Arco cosseno"
PythonAcosh = "Arc hyperbolic cosine" PythonAcosh = "Arco cosseno hiperbólico"
PythonAppend = "Add x to the end of the list" PythonAppend = "Adicionar x no fim da lista"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)" PythonArrow = "Seta de (x,y) para (x+dx,y+dy)"
PythonAsin = "Arc sine" PythonAsin = "Arco seno"
PythonAsinh = "Arc hyperbolic sine" PythonAsinh = "Arco seno hiperbólico"
PythonAtan = "Arc tangent" PythonAtan = "Arco tangente"
PythonAtan2 = "Return atan(y/x)" PythonAtan2 = "Cálculo de atan(y/x)"
PythonAtanh = "Arc hyperbolic tangent" PythonAtanh = "Arco tangente hiperbólica"
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)" PythonAxis = "Definir eixos (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values" PythonBar = "Gráfico de barras com valores de x"
PythonBin = "Convert integer to binary" PythonBin = "Converter número inteiro em binário"
PythonCeil = "Ceiling" PythonCeil = "Teto"
PythonChoice = "Random number in the list" PythonChoice = "Número aleatório na lista"
PythonClear = "Empty the list" PythonClear = "Esvaziar a lista"
PythonCmathFunction = "cmath module function prefix" PythonCmathFunction = "Prefixo da função do módulo cmath"
PythonColor = "Define a rgb color" PythonColor = "Define uma cor rgb"
PythonComplex = "Return a+ib" PythonColorBlack = "Cor preta"
PythonCopySign = "Return x with the sign of y" PythonColorBlue = "Cor azul"
PythonCos = "Cosine" PythonColorBrown = "Cor castanha"
PythonCosh = "Hyperbolic cosine" PythonColorGreen = "Cor verde"
PythonCount = "Count the occurrences of x" PythonColorGrey = "Cor cinzenta"
PythonDegrees = "Convert x from radians to degrees" PythonColorOrange = "Cor laranja"
PythonDivMod = "Quotient and remainder" PythonColorPink = "Cor rosa"
PythonDrawString = "Display a text from pixel (x,y)" PythonColorPurple = "Cor roxa"
PythonErf = "Error function" PythonColorRed = "Cor vermelha"
PythonErfc = "Complementary error function" PythonColorWhite = "Cor branca"
PythonEval = "Return the evaluated expression" PythonColorYellow = "Cor amarela"
PythonExp = "Exponential function" PythonComplex = "Devolve a+ib"
PythonExpm1 = "Compute exp(x)-1" PythonCopySign = "Devolve x com o sinal de y"
PythonFabs = "Absolute value" PythonCos = "Cosseno"
PythonFillRect = "Fill a rectangle at pixel (x,y)" PythonCosh = "Cosseno hiperbólico"
PythonFloat = "Convert x to a float" PythonCount = "Contar as ocorrências de x"
PythonFloor = "Floor" PythonDegrees = "Converter x de radianos para graus"
PythonFmod = "a modulo b" PythonDivMod = "Quociente e resto"
PythonFrExp = "Mantissa and exponent of x" PythonDrawString = "Mostrar o texto do pixel (x,y)"
PythonGamma = "Gamma function" PythonErf = "Função erro"
PythonGetPixel = "Return pixel (x,y) color" PythonErfc = "Função erro complementar"
PythonGetrandbits = "Integer with k random bits" PythonEval = "Devolve a expressão avaliada"
PythonGrid = "Toggle the visibility of the grid" PythonExp = "Função exponencial"
PythonHex = "Convert integer to hexadecimal" PythonExpm1 = "Calcular exp(x)-1"
PythonHist = "Draw the histogram of x" PythonFabs = "Valor absoluto"
PythonImportCmath = "Import cmath module" PythonFillRect = "Preencher um retângulo em (x,y)"
PythonImportIon = "Import ion module" PythonFloat = "Converter x num flutuante"
PythonImportKandinsky = "Import kandinsky module" PythonFloor = "Parte inteira"
PythonImportRandom = "Import random module" PythonFmod = "a módulo b"
PythonImportMath = "Import math module" PythonFrExp = "Coeficiente e expoente de x: (m, e)"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" PythonGamma = "Função gama"
PythonImportTime = "Import time module" PythonGetPixel = "Devolve a cor do pixel (x,y)"
PythonImportTurtle = "Import turtle module" PythonGetrandbits = "Número inteiro aleatório com k bits"
PythonIndex = "Index of the first x occurrence" PythonGrid = "Alterar visibilidade da grelha"
PythonInput = "Prompt a value" PythonHex = "Converter inteiro em hexadecimal"
PythonInsert = "Insert x at index i in the list" PythonHist = "Desenhar o histograma de x"
PythonInt = "Convert x to an integer" PythonImportCmath = "Importar módulo cmath"
PythonIonFunction = "ion module function prefix" PythonImportIon = "Importar módulo ion"
PythonIsFinite = "Check if x is finite" PythonImportKandinsky = "Importar módulo kandinsky"
PythonIsInfinite = "Check if x is infinity" PythonImportRandom = "Importar módulo random"
PythonIsKeyDown = "Return True if the k key is down" PythonImportMath = "Importar módulo math"
PythonIsNaN = "Check if x is a NaN" PythonImportMatplotlibPyplot = "Importar módulo matplotlib.pyplot"
PythonKandinskyFunction = "kandinsky module function prefix" PythonImportTime = "Importar módulo time"
PythonKeyLeft = "LEFT ARROW key" PythonImportTurtle = "Importar módulo turtle"
PythonKeyUp = "UP ARROW key" PythonIndex = "Índice da primeira ocorrência de x"
PythonKeyDown = "DOWN ARROW key" PythonInput = "Adicionar um valor"
PythonKeyRight = "RIGHT ARROW key" PythonInsert = "Inserir x no índice i na lista"
PythonKeyOk = "OK key" PythonInt = "Converter x num número inteiro"
PythonKeyBack = "BACK key" PythonIonFunction = "Prefixo da função do módulo ion"
PythonKeyHome = "HOME key" PythonIsFinite = "Verificar se x é finito"
PythonKeyOnOff = "ON/OFF key" PythonIsInfinite = "Verificar se x é infinito"
PythonKeyShift = "SHIFT key" PythonIsKeyDown = "Devolve True se tecla k pressionada"
PythonKeyAlpha = "ALPHA key" PythonIsNaN = "Verificar se x é um NaN"
PythonKeyXnt = "X,N,T key" PythonKandinskyFunction = "Prefixo da função do módulo kandinsky"
PythonKeyVar = "VAR key" PythonKeyLeft = "tecla SETA ESQUERDA"
PythonKeyToolbox = "TOOLBOX key" PythonKeyUp = "tecla SETA CIMA "
PythonKeyBackspace = "BACKSPACE key" PythonKeyDown = "tecla SETA BAIXO"
PythonKeyExp = "EXPONENTIAL key" PythonKeyRight = "tecla SETA DIREITA"
PythonKeyLn = "NATURAL LOGARITHM key" PythonKeyOk = "tecla OK"
PythonKeyLog = "DECIMAL LOGARITHM key" PythonKeyBack = "tecla VOLTAR"
PythonKeyImaginary = "IMAGINARY I key" PythonKeyHome = "tecla HOME"
PythonKeyComma = "COMMA key" PythonKeyOnOff = "tecla ON/OFF"
PythonKeyPower = "POWER key" PythonKeyShift = "tecla SHIFT"
PythonKeySine = "SINE key" PythonKeyAlpha = "tecla ALPHA"
PythonKeyCosine = "COSINE key" PythonKeyXnt = "tecla X,N,T"
PythonKeyTangent = "TANGENT key" PythonKeyVar = "tecla VAR"
PythonKeyPi = "PI key" PythonKeyToolbox = "tecla CAIXA DE FERRAMENTAS"
PythonKeySqrt = "SQUARE ROOT key" PythonKeyBackspace = "tecla APAGAR"
PythonKeySquare = "SQUARE key" PythonKeyExp = "tecla EXPONENCIAL"
PythonKeySeven = "7 key" PythonKeyLn = "tecla LOGARITMO NATURAL"
PythonKeyEight = "8 key" PythonKeyLog = "tecla LOGARITMO DECIMAL"
PythonKeyNine = "9 key" PythonKeyImaginary = "tecla I IMAGINÁRIO"
PythonKeyLeftParenthesis = "LEFT PARENTHESIS key" PythonKeyComma = "tecla VÍRGULA"
PythonKeyRightParenthesis = "RIGHT PARENTHESIS key" PythonKeyPower = "tecla EXPOENTE"
PythonKeyFour = "4 key" PythonKeySine = "tecla SENO"
PythonKeyFive = "5 key" PythonKeyCosine = "tecla COSSENO"
PythonKeySix = "6 key" PythonKeyTangent = "tecla TANGENTE"
PythonKeyMultiplication = "MULTIPLICATION key" PythonKeyPi = "tecla PI"
PythonKeyDivision = "DIVISION key" PythonKeySqrt = "tecla RAIZ QUADRADA"
PythonKeyOne = "1 key" PythonKeySquare = "tecla AO QUADRADO"
PythonKeyTwo = "2 key" PythonKeySeven = "tecla 7"
PythonKeyThree = "3 key" PythonKeyEight = "tecla 8"
PythonKeyPlus = "PLUS key" PythonKeyNine = "tecla 9"
PythonKeyMinus = "MINUS key" PythonKeyLeftParenthesis = "tecla PARÊNTESE ESQUERDO"
PythonKeyZero = "0 key" PythonKeyRightParenthesis = "tecla PARÊNTESE DIREITO"
PythonKeyDot = "DOT key" PythonKeyFour = "tecla 4"
PythonKeyEe = "10 POWER X key" PythonKeyFive = "tecla 5"
PythonKeyAns = "ANS key" PythonKeySix = "tecla 6"
PythonKeyExe = "EXE key" PythonKeyMultiplication = "tecla MULTIPLICAÇÃO"
PythonLdexp = "Return x*(2**i), inverse of frexp" PythonKeyDivision = "tecla DIVISÃO"
PythonLength = "Length of an object" PythonKeyOne = "tecla 1"
PythonLgamma = "Log-gamma function" PythonKeyTwo = "tecla 2"
PythonLog = "Logarithm to base a" PythonKeyThree = "tecla 3"
PythonLog10 = "Logarithm to base 10" PythonKeyPlus = "tecla MAIS"
PythonLog2 = "Logarithm to base 2" PythonKeyMinus = "tecla MENOS"
PythonMathFunction = "math module function prefix" PythonKeyZero = "tecla 0"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix" PythonKeyDot = "tecla PONTO"
PythonMax = "Maximum" PythonKeyEe = "tecla 10 expoente X"
PythonMin = "Minimum" PythonKeyAns = "tecla ANS"
PythonModf = "Fractional and integer parts of x" PythonKeyExe = "tecla EXE"
PythonMonotonic = "Value of a monotonic clock" PythonLdexp = "Devolve x*(2**i), inverso de frexp"
PythonOct = "Convert integer to octal" PythonLength = "Comprimento de um objeto"
PythonPhase = "Phase of z" PythonLgamma = "Logaritmo da função gama"
PythonPlot = "Plot y versus x as lines" PythonLog = "Logaritmo de base a"
PythonPolar = "z in polar coordinates" PythonLog10 = "Logaritmo de base 10"
PythonPop = "Remove and return the last item" PythonLog2 = "Logaritmo de base 2"
PythonPower = "x raised to the power y" PythonMathFunction = "Prefixo da função do módulo math"
PythonPrint = "Print object" PythonMatplotlibPyplotFunction = "Prefixo do módulo matplotlib.pyplot"
PythonRadians = "Convert x from degrees to radians" PythonMax = "Máximo"
PythonRandint = "Random integer in [a,b]" PythonMin = "Mínimo"
PythonRandom = "Floating point number in [0,1[" PythonModf = "Partes inteira e frácionária de x"
PythonRandomFunction = "random module function prefix" PythonMonotonic = "Devolve o valor do relógio"
PythonRandrange = "Random number in range(start, stop)" PythonOct = "Converter número inteiro em octal"
PythonRangeStartStop = "List from start to stop-1" PythonPhase = "Argumento de z"
PythonRangeStop = "List from 0 to stop-1" PythonPlot = "Desenhar y em função de x"
PythonRect = "z in cartesian coordinates" PythonPolar = "z em coordenadas polares"
PythonRemove = "Remove the first occurrence of x" PythonPop = "Remover o último item"
PythonReverse = "Reverse the elements of the list" PythonPower = "x levantado a y"
PythonRound = "Round to n digits" PythonPrint = "Mostrar o objeto"
PythonScatter = "Draw a scatter plot of y versus x" PythonRadians = "Converter x de graus para radianos"
PythonSeed = "Initialize random number generator" PythonRandint = "Número inteiro aleatório em [a,b]"
PythonSetPixel = "Color pixel (x,y)" PythonRandom = "Número decimal em [0,1["
PythonShow = "Display the figure" PythonRandomFunction = "Prefixo da função do módulo random"
PythonSin = "Sine" PythonRandrange = "Número aleatório em [start,stop-1]"
PythonSinh = "Hyperbolic sine" PythonRangeStartStop = "Lista de start a stop-1"
PythonSleep = "Suspend the execution for t seconds" PythonRangeStop = "Lista de 0 a stop-1"
PythonSort = "Sort the list" PythonRect = "Converter para coordenadas cartesianas"
PythonSqrt = "Square root" PythonRemove = "Remover a primeira ocorrência de x"
PythonSum = "Sum the items of a list" PythonReverse = "Inverter os elementos da lista"
PythonTan = "Tangent" PythonRound = "Arredondar para n dígitos"
PythonTanh = "Hyperbolic tangent" PythonScatter = "Gráfico de dispersão (x,y)"
PythonText = "Display a text at (x,y) coordinates" PythonSeed = "Iniciar gerador aleatório"
PythonTimeFunction = "time module function prefix" PythonSetPixel = "Cor do pixel (x,y)"
PythonTrunc = "x truncated to an integer" PythonShow = "Mostrar a figura"
PythonTurtleBackward = "Move backward by x pixels" PythonSin = "Seno"
PythonTurtleBlack = "Black color" PythonSinh = "Seno hiperbólico"
PythonTurtleBlue = "Blue color" PythonSleep = "Suspender a execução por t segundos"
PythonTurtleBrown = "Brown color" PythonSort = "Ordenar a lista"
PythonTurtleCircle = "Circle of radius r pixels" PythonSqrt = "Raiz quadrada"
PythonTurtleColor = "Set the pen color" PythonSum = "Soma dos itens da lista"
PythonTurtleForward = "Move forward by x pixels" PythonTan = "Tangente"
PythonTurtleFunction = "turtle module function prefix" PythonTanh = "Tangente hiperbólica"
PythonTurtleGoto = "Move to (x,y) coordinates" PythonText = "Mostrar um texto em (x,y)"
PythonTurtleGreen = "Green color" PythonTimeFunction = "Prefixo da função do módulo time"
PythonTurtleGrey = "Grey color" PythonTrunc = "x truncado a um número inteiro"
PythonTurtleHeading = "Return the current heading" PythonTurtleBackward = "Recuar x pixels"
PythonTurtleHideturtle = "Hide the turtle" PythonTurtleCircle = "Circunferência de raio r pixels"
PythonTurtleIsdown = "Return True if the pen is down" PythonTurtleColor = "Definir a cor da caneta"
PythonTurtleLeft = "Turn left by a degrees" PythonTurtleColorMode = "Define modo de cor para 1.0 ou 255"
PythonTurtleOrange = "Orange color" PythonTurtleForward = "Avançar x pixels"
PythonTurtlePendown = "Pull the pen down" PythonTurtleFunction = "Prefixo da função do módulo turtle"
PythonTurtlePensize = "Set the line thickness to x pixels" PythonTurtleGoto = "Ir paras as coordenadas (x,y)"
PythonTurtlePenup = "Pull the pen up" PythonTurtleHeading = "Voltar para a orientação atual"
PythonTurtlePink = "Pink color" PythonTurtleHideturtle = "Esconder o turtle"
PythonTurtlePosition = "Return the current (x,y) location" PythonTurtleIsdown = "True se a caneta está pressionada"
PythonTurtlePurple = "Purple color" PythonTurtleLeft = "Vira à esquerda por a graus"
PythonTurtleRed = "Red color" PythonTurtlePendown = "Puxar a caneta para baixo"
PythonTurtleReset = "Reset the drawing" PythonTurtlePensize = "Definir a espessura para x pixels"
PythonTurtleRight = "Turn right by a degrees" PythonTurtlePenup = "Puxar a caneta para cima"
PythonTurtleSetheading = "Set the orientation to a degrees" 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" PythonTurtleSetposition = "Positionne la tortue"
PythonTurtleShowturtle = "Show the turtle" PythonTurtleShowturtle = "Mostrar o turtle"
PythonTurtleSpeed = "Drawing speed between 0 and 10" PythonTurtleSpeed = "Velocidade do desenho entre 0 e 10"
PythonTurtleWhite = "White color" PythonTurtleWrite = "Mostrar um texto"
PythonTurtleYellow = "Yellow color" PythonUniform = "Número decimal em [a,b]"
PythonUniform = "Floating point number in [a,b]" PythonImportTime = "Import time module"
PythonTimeFromImport = "Import time module"
PythonTimeImport = "Import time module"
PythonTimePrefix = "time module function prefix" PythonTimePrefix = "time module function prefix"
PythonTimeSleep = "Aguardar n segundos" PythonTimeSleep = "Wait for n second"
PythonTimeMonotonic = "Retornar tempo monotônico" 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"

View File

@@ -29,6 +29,17 @@ PythonCommandClearWithoutArg = ".clear()"
PythonCommandCmathFunction = "cmath.function" PythonCommandCmathFunction = "cmath.function"
PythonCommandCmathFunctionWithoutArg = "cmath.\x11" PythonCommandCmathFunctionWithoutArg = "cmath.\x11"
PythonCommandColor = "color(r,g,b)" PythonCommandColor = "color(r,g,b)"
PythonCommandColorBlack = "'black'"
PythonCommandColorBlue = "'blue'"
PythonCommandColorBrown = "'brown'"
PythonCommandColorGreen = "'green'"
PythonCommandColorGrey = "'grey'"
PythonCommandColorOrange = "'orange'"
PythonCommandColorPink = "'pink'"
PythonCommandColorPurple = "'purple'"
PythonCommandColorRed = "'red'"
PythonCommandColorWhite = "'white'"
PythonCommandColorYellow = "'yellow'"
PythonCommandComplex = "complex(a,b)" PythonCommandComplex = "complex(a,b)"
PythonCommandConstantPi = "pi" PythonCommandConstantPi = "pi"
PythonCommandCopySign = "copysign(x,y)" PythonCommandCopySign = "copysign(x,y)"
@@ -154,7 +165,7 @@ PythonCommandModf = "modf(x)"
PythonCommandMonotonic = "monotonic()" PythonCommandMonotonic = "monotonic()"
PythonCommandOct = "oct(x)" PythonCommandOct = "oct(x)"
PythonCommandPhase = "phase(z)" PythonCommandPhase = "phase(z)"
PythonCommandPlot = "plot(x,y)" PythonCommandPlot = "plot(x,y,color)"
PythonCommandPolar = "polar(z)" PythonCommandPolar = "polar(z)"
PythonCommandPop = "list.pop()" PythonCommandPop = "list.pop()"
PythonCommandPopWithoutArg = ".pop()" PythonCommandPopWithoutArg = ".pop()"
@@ -165,17 +176,17 @@ PythonCommandRandint = "randint(a,b)"
PythonCommandRandom = "random()" PythonCommandRandom = "random()"
PythonCommandRandomFunction = "random.function" PythonCommandRandomFunction = "random.function"
PythonCommandRandomFunctionWithoutArg = "random.\x11" PythonCommandRandomFunctionWithoutArg = "random.\x11"
PythonCommandRandrange = "randrange(start, stop)" PythonCommandRandrange = "randrange(start,stop)"
PythonCommandRangeStartStop = "range(start, stop)" PythonCommandRangeStartStop = "range(start,stop)"
PythonCommandRangeStop = "range(stop)" PythonCommandRangeStop = "range(stop)"
PythonCommandReal = "z.real" PythonCommandReal = "z.real"
PythonCommandRealWithoutArg = ".real" PythonCommandRealWithoutArg = ".real"
PythonCommandRect = "rect(r, arg)" PythonCommandRect = "rect(r,arg)"
PythonCommandRemove = "list.remove(x)" PythonCommandRemove = "list.remove(x)"
PythonCommandRemoveWithoutArg = ".remove(\x11)" PythonCommandRemoveWithoutArg = ".remove(\x11)"
PythonCommandReverse = "list.reverse()" PythonCommandReverse = "list.reverse()"
PythonCommandReverseWithoutArg = ".reverse()" PythonCommandReverseWithoutArg = ".reverse()"
PythonCommandRound = "round(x, n)" PythonCommandRound = "round(x,n)"
PythonCommandScatter = "scatter(x,y)" PythonCommandScatter = "scatter(x,y)"
PythonCommandSeed = "seed(x)" PythonCommandSeed = "seed(x)"
PythonCommandSetPixel = "set_pixel(x,y,color)" PythonCommandSetPixel = "set_pixel(x,y,color)"
@@ -202,32 +213,23 @@ PythonCommandUniform = "uniform(a,b)"
PythonConstantE = "2.718281828459045" PythonConstantE = "2.718281828459045"
PythonConstantPi = "3.141592653589793" PythonConstantPi = "3.141592653589793"
PythonTurtleCommandBackward = "backward(x)" PythonTurtleCommandBackward = "backward(x)"
PythonTurtleCommandBlack = "'black'"
PythonTurtleCommandBlue = "'blue'"
PythonTurtleCommandBrown = "'brown'"
PythonTurtleCommandCircle = "circle(r)" PythonTurtleCommandCircle = "circle(r)"
PythonTurtleCommandColor = "color('c')/color(r,g,b)" PythonTurtleCommandColor = "color('c')"
PythonTurtleCommandColorWithoutArg = "color(\x11)" PythonTurtleCommandColorMode = "colormode(x)"
PythonTurtleCommandForward = "forward(x)" PythonTurtleCommandForward = "forward(x)"
PythonTurtleCommandGoto = "goto(x,y)" PythonTurtleCommandGoto = "goto(x,y)"
PythonTurtleCommandGreen = "'green'"
PythonTurtleCommandGrey = "'grey'"
PythonTurtleCommandHeading = "heading()" PythonTurtleCommandHeading = "heading()"
PythonTurtleCommandHideturtle = "hideturtle()" PythonTurtleCommandHideturtle = "hideturtle()"
PythonTurtleCommandIsdown= "isdown()" PythonTurtleCommandIsdown= "isdown()"
PythonTurtleCommandLeft = "left(a)" PythonTurtleCommandLeft = "left(a)"
PythonTurtleCommandOrange = "'orange'"
PythonTurtleCommandPendown = "pendown()" PythonTurtleCommandPendown = "pendown()"
PythonTurtleCommandPensize = "pensize(x)" PythonTurtleCommandPensize = "pensize(x)"
PythonTurtleCommandPenup = "penup()" PythonTurtleCommandPenup = "penup()"
PythonTurtleCommandPink = "'pink'"
PythonTurtleCommandPosition = "position()" PythonTurtleCommandPosition = "position()"
PythonTurtleCommandPurple = "'purple'"
PythonTurtleCommandRed = "'red'"
PythonTurtleCommandReset = "reset()" PythonTurtleCommandReset = "reset()"
PythonTurtleCommandRight = "right(a)" PythonTurtleCommandRight = "right(a)"
PythonTurtleCommandSetheading = "setheading(a)" PythonTurtleCommandSetheading = "setheading(a)"
PythonTurtleCommandSetposition = "setposition(x, [y])" PythonTurtleCommandSetposition = "setposition(x,[y])"
PythonTurtleCommandShowturtle = "showturtle()" PythonTurtleCommandShowturtle = "showturtle()"
PythonTurtleCommandSpeed = "speed(x)" PythonTurtleCommandSpeed = "speed(x)"
PythonTurtleCommandWhite = "'white'" PythonTurtleCommandWhite = "'white'"
@@ -237,3 +239,36 @@ PythonTimeCommandImportFrom = "from time import *"
PythonTimeCommandSleep = "sleep()" PythonTimeCommandSleep = "sleep()"
PythonTimeCommandSleepDemo = "sleep(n)" PythonTimeCommandSleepDemo = "sleep(n)"
PythonTimeCommandMonotonic = "monotonic()" PythonTimeCommandMonotonic = "monotonic()"
PythonCommandFileOpen = "open(name, [mode])"
PythonCommandFileOpenWithoutArg = "open(\x11)"
PythonCommandFileSeek = "file.seek(offset, [whence])"
PythonCommandFileSeekWithoutArg = ".seek(\x11)"
PythonCommandFileTell = "file.tell()"
PythonCommandFileTellWithoutArg = ".tell()"
PythonCommandFileSeekable = "file.seekable()"
PythonCommandFileSeekableWithoutArg = ".seekable()"
PythonCommandFileClose = "file.close()"
PythonCommandFileCloseWithoutArg = ".close()"
PythonCommandFileClosed = "file.closed"
PythonCommandFileClosedWithoutArg = ".closed"
PythonCommandFileRead = "file.read([size])"
PythonCommandFileReadWithoutArg = ".read(\x11)"
PythonCommandFileWrite = "file.write(b)"
PythonCommandFileWriteWithoutArg = ".write(\x11)"
PythonCommandFileReadline = "file.readline([size])"
PythonCommandFileReadlineWithoutArg = ".readline(\x11)"
PythonCommandFileReadlines = "file.readlines([hint])"
PythonCommandFileReadlinesWithoutArg = ".readlines(\x11)"
PythonCommandFileTruncate = "file.truncate([size])"
PythonCommandFileTruncateWithoutArg = ".truncate(\x11)"
PythonCommandFileWritelines = "file.writelines(lines)"
PythonCommandFileWritelinesWithoutArg = ".writelines(\x11)"
PythonCommandFileName = "file.name"
PythonCommandFileNameWithoutArg = ".name"
PythonCommandFileMode = "file.mode"
PythonCommandFileModeWithoutArg = ".mode"
PythonCommandFileReadable = "file.readable()"
PythonCommandFileReadableWithoutArg = ".readable()"
PythonCommandFileWritable = "file.writable()"
PythonCommandFileWritableWithoutArg = ".writable()"
PythonTurtleCommandWrite = "write(\"text\")"

View File

@@ -3,6 +3,7 @@
#include "script.h" #include "script.h"
#include "variable_box_controller.h" #include "variable_box_controller.h"
#include <apps/i18n.h> #include <apps/i18n.h>
#include <algorithm>
#include <assert.h> #include <assert.h>
#include <escher/metric.h> #include <escher/metric.h>
#include <poincare/preferences.h> #include <poincare/preferences.h>
@@ -16,8 +17,6 @@ extern "C" {
namespace Code { namespace Code {
static inline int minInt(int x, int y) { return x < y ? x : y; }
static const char * sStandardPromptText = ">>> "; static const char * sStandardPromptText = ">>> ";
ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore
@@ -32,7 +31,7 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe
m_pythonDelegate(pythonDelegate), m_pythonDelegate(pythonDelegate),
m_importScriptsWhenViewAppears(false), m_importScriptsWhenViewAppears(false),
m_selectableTableView(this, this, this, this), m_selectableTableView(this, this, this, this),
m_editCell(this, pythonDelegate, this), m_editCell(this, this, this),
m_scriptStore(scriptStore), m_scriptStore(scriptStore),
m_sandboxController(this), m_sandboxController(this),
m_inputRunLoopActive(false) m_inputRunLoopActive(false)
@@ -49,17 +48,13 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe
} }
bool ConsoleController::loadPythonEnvironment() { bool ConsoleController::loadPythonEnvironment() {
if (m_pythonDelegate->isPythonUser(this)) { if (!m_pythonDelegate->isPythonUser(this)) {
return true; m_scriptStore->clearConsoleFetchInformation();
emptyOutputAccumulationBuffer();
m_pythonDelegate->initPythonWithUser(this);
MicroPython::registerScriptProvider(m_scriptStore);
m_importScriptsWhenViewAppears = m_autoImportScripts;
} }
emptyOutputAccumulationBuffer();
m_pythonDelegate->initPythonWithUser(this);
MicroPython::registerScriptProvider(m_scriptStore);
m_importScriptsWhenViewAppears = m_autoImportScripts;
/* We load functions and variables names in the variable box before running
* any other python code to avoid failling to load functions and variables
* due to memory exhaustion. */
App::app()->variableBoxController()->loadFunctionsAndVariables();
return true; return true;
} }
@@ -291,7 +286,7 @@ void ConsoleController::willDisplayCellAtLocation(HighlightCell * cell, int i, i
} }
} }
void ConsoleController::tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) { void ConsoleController::tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) {
if (withinTemporarySelection) { if (withinTemporarySelection) {
return; return;
} }
@@ -376,6 +371,14 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) {
return true; return true;
} }
VariableBoxController * ConsoleController::variableBoxForInputEventHandler(InputEventHandler * textInput) {
VariableBoxController * varBox = App::app()->variableBoxController();
varBox->loadVariablesImportedFromScripts();
varBox->setTitle(I18n::Message::FunctionsAndVariables);
varBox->setDisplaySubtitles(false);
return varBox;
}
void ConsoleController::resetSandbox() { void ConsoleController::resetSandbox() {
if (stackViewController()->topViewController() != sandbox()) { if (stackViewController()->topViewController() != sandbox()) {
return; return;
@@ -448,7 +451,7 @@ void ConsoleController::printText(const char * text, size_t length) {
flushOutputAccumulationBufferToStore(); flushOutputAccumulationBufferToStore();
micropython_port_vm_hook_refresh_print(); micropython_port_vm_hook_refresh_print();
} }
#if __EMSCRIPTEN__ // #if __EMSCRIPTEN__
/* If we called micropython_port_interrupt_if_needed here, we would need to /* If we called micropython_port_interrupt_if_needed here, we would need to
* put in the WHITELIST all the methods that call * put in the WHITELIST all the methods that call
* ConsoleController::printText, which means all the MicroPython methods that * ConsoleController::printText, which means all the MicroPython methods that
@@ -461,13 +464,17 @@ void ConsoleController::printText(const char * text, size_t length) {
* device. * device.
* *
* TODO: Allow print interrpution on emscripten -> maybe by using WASM=1 ? */ * TODO: Allow print interrpution on emscripten -> maybe by using WASM=1 ? */
#else
/*
* This can be run in Omega, since it uses WebASM.
*/
// #else
/* micropython_port_vm_hook_loop is not enough to detect user interruptions, /* micropython_port_vm_hook_loop is not enough to detect user interruptions,
* because it calls micropython_port_interrupt_if_needed every 20000 * because it calls micropython_port_interrupt_if_needed every 20000
* operations, and a print operation is quite long. We thus explicitely call * operations, and a print operation is quite long. We thus explicitely call
* micropython_port_interrupt_if_needed here. */ * micropython_port_interrupt_if_needed here. */
micropython_port_interrupt_if_needed(); micropython_port_interrupt_if_needed();
#endif // #endif
} }
void ConsoleController::autoImportScript(Script script, bool force) { void ConsoleController::autoImportScript(Script script, bool force) {
@@ -476,7 +483,7 @@ void ConsoleController::autoImportScript(Script script, bool force) {
* the sandbox. */ * the sandbox. */
hideAnyDisplayedViewController(); hideAnyDisplayedViewController();
if (script.importationStatus() || force) { if (script.autoImportationStatus() || force) {
// Step 1 - Create the command "from scriptName import *". // Step 1 - Create the command "from scriptName import *".
assert(strlen(k_importCommand1) + strlen(script.fullName()) - strlen(ScriptStore::k_scriptExtension) - 1 + strlen(k_importCommand2) + 1 <= k_maxImportCommandSize); assert(strlen(k_importCommand1) + strlen(script.fullName()) - strlen(ScriptStore::k_scriptExtension) - 1 + strlen(k_importCommand2) + 1 <= k_maxImportCommandSize);
@@ -488,7 +495,7 @@ void ConsoleController::autoImportScript(Script script, bool force) {
/* Copy the script name without the extension ".py". The '.' is overwritten /* Copy the script name without the extension ".py". The '.' is overwritten
* by the null terminating char. */ * by the null terminating char. */
int copySizeWithNullTerminatingZero = minInt(k_maxImportCommandSize - currentChar, strlen(scriptName) - strlen(ScriptStore::k_scriptExtension)); int copySizeWithNullTerminatingZero = std::min(k_maxImportCommandSize - currentChar, strlen(scriptName) - strlen(ScriptStore::k_scriptExtension));
assert(copySizeWithNullTerminatingZero >= 0); assert(copySizeWithNullTerminatingZero >= 0);
assert(copySizeWithNullTerminatingZero <= k_maxImportCommandSize - currentChar); assert(copySizeWithNullTerminatingZero <= k_maxImportCommandSize - currentChar);
strlcpy(command+currentChar, scriptName, copySizeWithNullTerminatingZero); strlcpy(command+currentChar, scriptName, copySizeWithNullTerminatingZero);

View File

@@ -10,12 +10,14 @@
#include "console_store.h" #include "console_store.h"
#include "sandbox_controller.h" #include "sandbox_controller.h"
#include "script_store.h" #include "script_store.h"
#include "variable_box_controller.h"
#include "../shared/input_event_handler_delegate.h"
namespace Code { namespace Code {
class App; class App;
class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public MicroPython::ExecutionEnvironment { class ConsoleController : public ViewController, public ListViewDataSource, public SelectableTableViewDataSource, public SelectableTableViewDelegate, public TextFieldDelegate, public Shared::InputEventHandlerDelegate, public MicroPython::ExecutionEnvironment {
public: public:
ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore ConsoleController(Responder * parentResponder, App * pythonDelegate, ScriptStore * scriptStore
#if EPSILON_GETOPT #if EPSILON_GETOPT
@@ -52,7 +54,7 @@ public:
void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override; void willDisplayCellAtLocation(HighlightCell * cell, int i, int j) override;
// SelectableTableViewDelegate // SelectableTableViewDelegate
void tableViewDidChangeSelection(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override; void tableViewDidChangeSelectionAndDidScroll(SelectableTableView * t, int previousSelectedCellX, int previousSelectedCellY, bool withinTemporarySelection) override;
// TextFieldDelegate // TextFieldDelegate
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override; bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
@@ -60,6 +62,9 @@ public:
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override; bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
bool textFieldDidAbortEditing(TextField * textField) override; bool textFieldDidAbortEditing(TextField * textField) override;
// InputEventHandlerDelegate
VariableBoxController * variableBoxForInputEventHandler(InputEventHandler * textInput) override;
// MicroPython::ExecutionEnvironment // MicroPython::ExecutionEnvironment
ViewController * sandbox() override { return &m_sandboxController; } ViewController * sandbox() override { return &m_sandboxController; }
void resetSandbox() override; void resetSandbox() override;

View File

@@ -4,11 +4,10 @@
#include <apps/i18n.h> #include <apps/i18n.h>
#include <apps/global_preferences.h> #include <apps/global_preferences.h>
#include <assert.h> #include <assert.h>
#include <algorithm>
namespace Code { namespace Code {
static inline int minInt(int x, int y) { return x < y ? x : y; }
ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * delegate) : ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * delegate) :
HighlightCell(), HighlightCell(),
Responder(parentResponder), Responder(parentResponder),
@@ -70,7 +69,7 @@ const char * ConsoleEditCell::shiftCurrentTextAndClear() {
char * textFieldBuffer = const_cast<char *>(m_textField.text()); char * textFieldBuffer = const_cast<char *>(m_textField.text());
char * newTextPosition = textFieldBuffer + 1; char * newTextPosition = textFieldBuffer + 1;
assert(previousBufferSize > 0); assert(previousBufferSize > 0);
size_t copyLength = minInt(previousBufferSize - 1, strlen(textFieldBuffer)); size_t copyLength = std::min(previousBufferSize - 1, strlen(textFieldBuffer));
memmove(newTextPosition, textFieldBuffer, copyLength); memmove(newTextPosition, textFieldBuffer, copyLength);
newTextPosition[copyLength] = 0; newTextPosition[copyLength] = 0;
textFieldBuffer[0] = 0; textFieldBuffer[0] = 0;

View File

@@ -19,7 +19,7 @@ void ConsoleLineCell::ScrollableConsoleLineView::ConsoleLineView::setLine(Consol
void ConsoleLineCell::ScrollableConsoleLineView::ConsoleLineView::drawRect(KDContext * ctx, KDRect rect) const { void ConsoleLineCell::ScrollableConsoleLineView::ConsoleLineView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->fillRect(bounds(), Palette::CodeBackground); ctx->fillRect(bounds(), Palette::CodeBackground);
ctx->drawString(m_line->text(), KDPointZero, GlobalPreferences::sharedGlobalPreferences()->font(), textColor(m_line), isHighlighted()? Palette::Select : KDColorWhite); ctx->drawString(m_line->text(), KDPointZero, GlobalPreferences::sharedGlobalPreferences()->font(), textColor(m_line), isHighlighted()? Palette::Select : Palette::BackgroundApps);
} }
KDSize ConsoleLineCell::ScrollableConsoleLineView::ConsoleLineView::minimalSizeForOptimalDisplay() const { KDSize ConsoleLineCell::ScrollableConsoleLineView::ConsoleLineView::minimalSizeForOptimalDisplay() const {

View File

@@ -1,10 +1,9 @@
#include "console_store.h" #include "console_store.h"
#include <string.h> #include <string.h>
#include <algorithm>
namespace Code { namespace Code {
static inline int minInt(int x, int y) { return x < y ? x : y; }
void ConsoleStore::startNewSession() { void ConsoleStore::startNewSession() {
if (k_historySize < 1) { if (k_historySize < 1) {
return; return;
@@ -12,7 +11,7 @@ void ConsoleStore::startNewSession() {
m_history[0] = makePrevious(m_history[0]); m_history[0] = makePrevious(m_history[0]);
for (int i = 0; i < k_historySize - 1; i++) { for (size_t i = 0; i < k_historySize - 1; i++) {
if (m_history[i] == 0) { if (m_history[i] == 0) {
if (m_history[i+1] == 0) { if (m_history[i+1] == 0) {
return ; return ;
@@ -25,7 +24,7 @@ void ConsoleStore::startNewSession() {
ConsoleLine ConsoleStore::lineAtIndex(int i) const { ConsoleLine ConsoleStore::lineAtIndex(int i) const {
assert(i >= 0 && i < numberOfLines()); assert(i >= 0 && i < numberOfLines());
int currentLineIndex = 0; int currentLineIndex = 0;
for (int j=0; j<k_historySize; j++) { for (size_t j=0; j<k_historySize; j++) {
if (m_history[j] == 0) { if (m_history[j] == 0) {
currentLineIndex++; currentLineIndex++;
j++; j++;
@@ -43,7 +42,7 @@ int ConsoleStore::numberOfLines() const {
return 0; return 0;
} }
int result = 0; int result = 0;
for (int i = 0; i < k_historySize - 1; i++) { for (size_t i = 0; i < k_historySize - 1; i++) {
if (m_history[i] == 0) { if (m_history[i] == 0) {
result++; result++;
if (m_history[i+1] == 0) { if (m_history[i+1] == 0) {
@@ -96,14 +95,14 @@ const char * ConsoleStore::push(const char marker, const char * text) {
if (ConsoleLine::sizeOfConsoleLine(textLength) > k_historySize - 1) { if (ConsoleLine::sizeOfConsoleLine(textLength) > k_historySize - 1) {
textLength = k_historySize - 1 - 1 - 1; // Marker, null termination and null marker. textLength = k_historySize - 1 - 1 - 1; // Marker, null termination and null marker.
} }
int i = indexOfNullMarker(); size_t i = indexOfNullMarker();
// If needed, make room for the text we want to push. // If needed, make room for the text we want to push.
while (i + ConsoleLine::sizeOfConsoleLine(textLength) > k_historySize - 1) { while (i + ConsoleLine::sizeOfConsoleLine(textLength) > k_historySize - 1) {
deleteFirstLine(); deleteFirstLine();
i = indexOfNullMarker(); i = indexOfNullMarker();
} }
m_history[i] = marker; m_history[i] = marker;
strlcpy(&m_history[i+1], text, minInt(k_historySize-(i+1),textLength+1)); strlcpy(&m_history[i+1], text, std::min(k_historySize-(i+1),textLength+1));
m_history[i+1+textLength+1] = 0; m_history[i+1+textLength+1] = 0;
return &m_history[i+1]; return &m_history[i+1];
} }
@@ -113,11 +112,11 @@ ConsoleLine::Type ConsoleStore::lineTypeForMarker(char marker) const {
return static_cast<ConsoleLine::Type>(marker-1); return static_cast<ConsoleLine::Type>(marker-1);
} }
int ConsoleStore::indexOfNullMarker() const { size_t ConsoleStore::indexOfNullMarker() const {
if (m_history[0] == 0) { if (m_history[0] == 0) {
return 0; return 0;
} }
for (int i=0; i<k_historySize; i++) { for (size_t i=0; i<k_historySize; i++) {
if (m_history[i] == 0 && m_history[i+1] == 0) { if (m_history[i] == 0 && m_history[i+1] == 0) {
return (i+1); return (i+1);
} }
@@ -129,13 +128,13 @@ int ConsoleStore::indexOfNullMarker() const {
void ConsoleStore::deleteLineAtIndex(int index) { void ConsoleStore::deleteLineAtIndex(int index) {
assert(index >=0 && index < numberOfLines()); assert(index >=0 && index < numberOfLines());
int currentLineIndex = 0; int currentLineIndex = 0;
for (int i = 0; i < k_historySize - 1; i++) { for (size_t i = 0; i < k_historySize - 1; i++) {
if (m_history[i] == 0) { if (m_history[i] == 0) {
currentLineIndex++; currentLineIndex++;
continue; continue;
} }
if (currentLineIndex == index) { if (currentLineIndex == index) {
int nextLineStart = i; size_t nextLineStart = i;
while (m_history[nextLineStart] != 0 && nextLineStart < k_historySize - 2) { while (m_history[nextLineStart] != 0 && nextLineStart < k_historySize - 2) {
nextLineStart++; nextLineStart++;
} }
@@ -158,7 +157,7 @@ void ConsoleStore::deleteFirstLine() {
secondLineMarkerIndex++; secondLineMarkerIndex++;
} }
secondLineMarkerIndex++; secondLineMarkerIndex++;
for (int i=0; i<k_historySize - secondLineMarkerIndex; i++) { for (size_t i=0; i<k_historySize - secondLineMarkerIndex; i++) {
m_history[i] = m_history[secondLineMarkerIndex+i]; m_history[i] = m_history[secondLineMarkerIndex+i];
} }
} }
@@ -174,7 +173,7 @@ void ConsoleStore::deleteLastLine() {
} }
int currentLineIndex = 1; int currentLineIndex = 1;
int lastLineMarkerIndex = 0; int lastLineMarkerIndex = 0;
for (int i=0; i<k_historySize; i++) { for (size_t i=0; i<k_historySize; i++) {
if (m_history[i] == 0) { if (m_history[i] == 0) {
currentLineIndex++; currentLineIndex++;
if (currentLineIndex == lineCount) { if (currentLineIndex == lineCount) {

View File

@@ -23,7 +23,7 @@ private:
static constexpr char CurrentSessionResultMarker = 0x02; static constexpr char CurrentSessionResultMarker = 0x02;
static constexpr char PreviousSessionCommandMarker = 0x03; static constexpr char PreviousSessionCommandMarker = 0x03;
static constexpr char PreviousSessionResultMarker = 0x04; static constexpr char PreviousSessionResultMarker = 0x04;
static constexpr int k_historySize = 1024; static constexpr size_t k_historySize = 1024;
static char makePrevious(char marker) { static char makePrevious(char marker) {
if (marker == CurrentSessionCommandMarker || marker == CurrentSessionResultMarker) { if (marker == CurrentSessionCommandMarker || marker == CurrentSessionResultMarker) {
return marker + 0x02; return marker + 0x02;
@@ -32,7 +32,7 @@ private:
} }
const char * push(const char marker, const char * text); const char * push(const char marker, const char * text);
ConsoleLine::Type lineTypeForMarker(char marker) const; ConsoleLine::Type lineTypeForMarker(char marker) const;
int indexOfNullMarker() const; size_t indexOfNullMarker() const;
void deleteLineAtIndex(int index); void deleteLineAtIndex(int index);
void deleteFirstLine(); void deleteFirstLine();
/* When there is no room left to store a new ConsoleLine, we have to delete /* When there is no room left to store a new ConsoleLine, we have to delete

View File

@@ -13,13 +13,15 @@ EditorController::EditorController(MenuController * menuController, App * python
ViewController(nullptr), ViewController(nullptr),
m_editorView(this, pythonDelegate), m_editorView(this, pythonDelegate),
m_script(Ion::Storage::Record()), m_script(Ion::Storage::Record()),
m_scriptIndex(-1),
m_menuController(menuController) m_menuController(menuController)
{ {
m_editorView.setTextAreaDelegates(this, this); m_editorView.setTextAreaDelegates(this, this);
} }
void EditorController::setScript(Script script) { void EditorController::setScript(Script script, int scriptIndex) {
m_script = script; m_script = script;
m_scriptIndex = scriptIndex;
/* We edit the script direclty in the storage buffer. We thus put all the /* We edit the script direclty in the storage buffer. We thus put all the
* storage available space at the end of the current edited script and we set * storage available space at the end of the current edited script and we set
@@ -35,7 +37,7 @@ void EditorController::setScript(Script script) {
* */ * */
size_t newScriptSize = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(m_script); size_t newScriptSize = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(m_script);
m_editorView.setText(const_cast<char *>(m_script.scriptContent()), newScriptSize - Script::k_importationStatusSize); m_editorView.setText(const_cast<char *>(m_script.content()), newScriptSize - Script::StatusSize());
} }
void EditorController::willExitApp() { void EditorController::willExitApp() {
@@ -78,14 +80,6 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
return true; return true;
} }
if(event.hasText()){
if(event.text() == "%" && Ion::Events::isLockActive() ){
return textArea->removePreviousGlyph();
} else {
return textArea->handleEventWithText(event.text(), true, false);
}
}
if (event == Ion::Events::Backspace && textArea->selectionIsEmpty()) { if (event == Ion::Events::Backspace && textArea->selectionIsEmpty()) {
/* If the cursor is on the left of the text of a line, backspace one /* If the cursor is on the left of the text of a line, backspace one
@@ -131,7 +125,24 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) { VariableBoxController * EditorController::variableBoxForInputEventHandler(InputEventHandler * textInput) {
VariableBoxController * varBox = App::app()->variableBoxController(); VariableBoxController * varBox = App::app()->variableBoxController();
varBox->loadFunctionsAndVariables(); /* If the editor should be autocompleting an identifier, the variable box has
* already been loaded. We check shouldAutocomplete and not isAutocompleting,
* because the autocompletion result might be empty. */
const char * beginningOfAutocompletion = nullptr;
const char * cursor = nullptr;
PythonTextArea::AutocompletionType autocompType = m_editorView.autocompletionType(&beginningOfAutocompletion, &cursor);
if (autocompType == PythonTextArea::AutocompletionType::NoIdentifier) {
varBox->loadFunctionsAndVariables(m_scriptIndex, nullptr, 0);
} else if (autocompType == PythonTextArea::AutocompletionType::MiddleOfIdentifier) {
varBox->empty();
} else {
assert(autocompType == PythonTextArea::AutocompletionType::EndOfIdentifier);
assert(beginningOfAutocompletion != nullptr && cursor != nullptr);
assert(cursor > beginningOfAutocompletion);
varBox->loadFunctionsAndVariables(m_scriptIndex, beginningOfAutocompletion, cursor - beginningOfAutocompletion);
}
varBox->setTitle(I18n::Message::Autocomplete);
varBox->setDisplaySubtitles(true);
return varBox; return varBox;
} }
@@ -146,7 +157,7 @@ void EditorController::cleanStorageEmptySpace() {
Ion::Storage::Record::Data scriptValue = m_script.value(); Ion::Storage::Record::Data scriptValue = m_script.value();
Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord( Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord(
m_script, m_script,
scriptValue.size - Script::k_importationStatusSize - (strlen(m_script.scriptContent()) + 1)); // TODO optimize number of script fetches scriptValue.size - Script::StatusSize() - (strlen(m_script.content()) + 1)); // TODO optimize number of script fetches
} }

View File

@@ -16,7 +16,8 @@ class App;
class EditorController : public ViewController, public TextAreaDelegate, public Shared::InputEventHandlerDelegate { class EditorController : public ViewController, public TextAreaDelegate, public Shared::InputEventHandlerDelegate {
public: public:
EditorController(MenuController * menuController, App * pythonDelegate); EditorController(MenuController * menuController, App * pythonDelegate);
void setScript(Script script); void setScript(Script script, int scriptIndex);
int scriptIndex() const { return m_scriptIndex; }
void willExitApp(); void willExitApp();
/* ViewController */ /* ViewController */
@@ -39,6 +40,7 @@ private:
StackViewController * stackController(); StackViewController * stackController();
EditorView m_editorView; EditorView m_editorView;
Script m_script; Script m_script;
int m_scriptIndex;
MenuController * m_menuController; MenuController * m_menuController;
}; };

View File

@@ -17,6 +17,10 @@ EditorView::EditorView(Responder * parentResponder, App * pythonDelegate) :
m_textArea.setScrollViewDelegate(this); m_textArea.setScrollViewDelegate(this);
} }
bool EditorView::isAutocompleting() const {
return m_textArea.isAutocompleting();
}
void EditorView::resetSelection() { void EditorView::resetSelection() {
m_textArea.resetSelection(); m_textArea.resetSelection();
} }
@@ -53,8 +57,8 @@ void EditorView::layoutSubviews(bool force) {
/* EditorView::GutterView */ /* EditorView::GutterView */
void EditorView::GutterView::drawRect(KDContext * ctx, KDRect rect) const { void EditorView::GutterView::drawRect(KDContext * ctx, KDRect rect) const {
KDColor textColor = KDColor::RGB24(0x919EA4); KDColor textColor = Palette::PrimaryText;
KDColor backgroundColor = KDColor::RGB24(0xE4E6E7); KDColor backgroundColor = Palette::CodeGutterViewBackground;
ctx->fillRect(rect, backgroundColor); ctx->fillRect(rect, backgroundColor);

View File

@@ -9,6 +9,8 @@ namespace Code {
class EditorView : public Responder, public View, public ScrollViewDelegate { class EditorView : public Responder, public View, public ScrollViewDelegate {
public: public:
EditorView(Responder * parentResponder, App * pythonDelegate); EditorView(Responder * parentResponder, App * pythonDelegate);
PythonTextArea::AutocompletionType autocompletionType(const char ** autocompletionBeginning, const char ** autocompletionEnd) const { return m_textArea.autocompletionType(nullptr, autocompletionBeginning, autocompletionEnd); }
bool isAutocompleting() const;
void resetSelection(); void resetSelection();
void setTextAreaDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) { void setTextAreaDelegates(InputEventHandlerDelegate * inputEventHandlerDelegate, TextAreaDelegate * delegate) {
m_textArea.setDelegates(inputEventHandlerDelegate, delegate); m_textArea.setDelegates(inputEventHandlerDelegate, delegate);
@@ -17,6 +19,9 @@ public:
void setText(char * textBuffer, size_t textBufferSize) { void setText(char * textBuffer, size_t textBufferSize) {
m_textArea.setText(textBuffer, textBufferSize); m_textArea.setText(textBuffer, textBufferSize);
} }
const char * cursorLocation() {
return m_textArea.cursorLocation();
}
bool setCursorLocation(const char * location) { bool setCursorLocation(const char * location) {
return m_textArea.setCursorLocation(location); return m_textArea.setCursorLocation(location);
} }

View File

@@ -385,7 +385,7 @@ void MenuController::configureScript() {
void MenuController::editScriptAtIndex(int scriptIndex) { void MenuController::editScriptAtIndex(int scriptIndex) {
assert(scriptIndex >=0 && scriptIndex < m_scriptStore->numberOfScripts()); assert(scriptIndex >=0 && scriptIndex < m_scriptStore->numberOfScripts());
Script script = m_scriptStore->scriptAtIndex(scriptIndex); Script script = m_scriptStore->scriptAtIndex(scriptIndex);
m_editorController.setScript(script); m_editorController.setScript(script, scriptIndex);
stackViewController()->push(&m_editorController); stackViewController()->push(&m_editorController);
} }

View File

@@ -25,6 +25,7 @@ public:
void openConsoleWithScript(Script script); void openConsoleWithScript(Script script);
void scriptContentEditionDidFinish(); void scriptContentEditionDidFinish();
void willExitApp(); void willExitApp();
int editedScriptIndex() const { return m_editorController.scriptIndex(); }
/* ViewController */ /* ViewController */
View * view() override { return &m_selectableTableView; } View * view() override { return &m_selectableTableView; }

View File

@@ -9,6 +9,7 @@ extern "C" {
#include "py/lexer.h" #include "py/lexer.h"
} }
#include <stdlib.h> #include <stdlib.h>
#include <algorithm>
namespace Code { namespace Code {
@@ -20,8 +21,7 @@ constexpr KDColor OperatorColor = Palette::CodeOperator;
constexpr KDColor StringColor = Palette::CodeString; constexpr KDColor StringColor = Palette::CodeString;
constexpr KDColor BackgroundColor = Palette::CodeBackground; constexpr KDColor BackgroundColor = Palette::CodeBackground;
constexpr KDColor HighlightColor = Palette::CodeBackgroundSelected; constexpr KDColor HighlightColor = Palette::CodeBackgroundSelected;
constexpr KDColor AutocompleteColor = KDColor::RGB24(0xC6C6C6); // TODO Palette change
static inline const char * minPointer(const char * x, const char * y) { return x < y ? x : y; }
static inline KDColor TokenColor(mp_token_kind_t tokenKind) { static inline KDColor TokenColor(mp_token_kind_t tokenKind) {
if (tokenKind == MP_TOKEN_STRING) { if (tokenKind == MP_TOKEN_STRING) {
@@ -30,13 +30,96 @@ static inline KDColor TokenColor(mp_token_kind_t tokenKind) {
if (tokenKind == MP_TOKEN_INTEGER || tokenKind == MP_TOKEN_FLOAT_OR_IMAG) { if (tokenKind == MP_TOKEN_INTEGER || tokenKind == MP_TOKEN_FLOAT_OR_IMAG) {
return NumberColor; return NumberColor;
} }
static_assert(MP_TOKEN_ELLIPSIS + 1 == MP_TOKEN_KW_FALSE
&& MP_TOKEN_KW_FALSE + 1 == MP_TOKEN_KW_NONE
&& MP_TOKEN_KW_NONE + 1 == MP_TOKEN_KW_TRUE
&& MP_TOKEN_KW_TRUE + 1 == MP_TOKEN_KW___DEBUG__
&& MP_TOKEN_KW___DEBUG__ + 1 == MP_TOKEN_KW_AND
&& MP_TOKEN_KW_AND + 1 == MP_TOKEN_KW_AS
&& MP_TOKEN_KW_AS + 1 == MP_TOKEN_KW_ASSERT
/* Here there are keywords that depend on MICROPY_PY_ASYNC_AWAIT, we do
* not test them */
&& MP_TOKEN_KW_BREAK + 1 == MP_TOKEN_KW_CLASS
&& MP_TOKEN_KW_CLASS + 1 == MP_TOKEN_KW_CONTINUE
&& MP_TOKEN_KW_CONTINUE + 1 == MP_TOKEN_KW_DEF
&& MP_TOKEN_KW_DEF + 1 == MP_TOKEN_KW_DEL
&& MP_TOKEN_KW_DEL + 1 == MP_TOKEN_KW_ELIF
&& MP_TOKEN_KW_ELIF + 1 == MP_TOKEN_KW_ELSE
&& MP_TOKEN_KW_ELSE + 1 == MP_TOKEN_KW_EXCEPT
&& MP_TOKEN_KW_EXCEPT + 1 == MP_TOKEN_KW_FINALLY
&& MP_TOKEN_KW_FINALLY + 1 == MP_TOKEN_KW_FOR
&& MP_TOKEN_KW_FOR + 1 == MP_TOKEN_KW_FROM
&& MP_TOKEN_KW_FROM + 1 == MP_TOKEN_KW_GLOBAL
&& MP_TOKEN_KW_GLOBAL + 1 == MP_TOKEN_KW_IF
&& MP_TOKEN_KW_IF + 1 == MP_TOKEN_KW_IMPORT
&& MP_TOKEN_KW_IMPORT + 1 == MP_TOKEN_KW_IN
&& MP_TOKEN_KW_IN + 1 == MP_TOKEN_KW_IS
&& MP_TOKEN_KW_IS + 1 == MP_TOKEN_KW_LAMBDA
&& MP_TOKEN_KW_LAMBDA + 1 == MP_TOKEN_KW_NONLOCAL
&& MP_TOKEN_KW_NONLOCAL + 1 == MP_TOKEN_KW_NOT
&& MP_TOKEN_KW_NOT + 1 == MP_TOKEN_KW_OR
&& MP_TOKEN_KW_OR + 1 == MP_TOKEN_KW_PASS
&& MP_TOKEN_KW_PASS + 1 == MP_TOKEN_KW_RAISE
&& MP_TOKEN_KW_RAISE + 1 == MP_TOKEN_KW_RETURN
&& MP_TOKEN_KW_RETURN + 1 == MP_TOKEN_KW_TRY
&& 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 order changed, so Code::PythonTextArea::TokenColor might need to change too.");
if (tokenKind >= MP_TOKEN_KW_FALSE && tokenKind <= MP_TOKEN_KW_YIELD) { if (tokenKind >= MP_TOKEN_KW_FALSE && tokenKind <= MP_TOKEN_KW_YIELD) {
return KeywordColor; return KeywordColor;
} }
if (tokenKind >= MP_TOKEN_OP_PLUS && tokenKind <= MP_TOKEN_OP_NOT_EQUAL) { static_assert(MP_TOKEN_OP_TILDE + 1 == MP_TOKEN_OP_LESS
return OperatorColor; && MP_TOKEN_OP_LESS + 1 == MP_TOKEN_OP_MORE
} && MP_TOKEN_OP_MORE + 1 == MP_TOKEN_OP_DBL_EQUAL
if (tokenKind >= MP_TOKEN_DEL_EQUAL && tokenKind <= MP_TOKEN_DEL_MINUS_MORE) { && MP_TOKEN_OP_DBL_EQUAL + 1 == MP_TOKEN_OP_LESS_EQUAL
&& MP_TOKEN_OP_LESS_EQUAL + 1 == MP_TOKEN_OP_MORE_EQUAL
&& MP_TOKEN_OP_MORE_EQUAL + 1 == MP_TOKEN_OP_NOT_EQUAL
&& MP_TOKEN_OP_NOT_EQUAL + 1 == MP_TOKEN_OP_PIPE
&& MP_TOKEN_OP_PIPE + 1 == MP_TOKEN_OP_CARET
&& MP_TOKEN_OP_CARET + 1 == MP_TOKEN_OP_AMPERSAND
&& MP_TOKEN_OP_AMPERSAND + 1 == MP_TOKEN_OP_DBL_LESS
&& MP_TOKEN_OP_DBL_LESS + 1 == MP_TOKEN_OP_DBL_MORE
&& MP_TOKEN_OP_DBL_MORE + 1 == MP_TOKEN_OP_PLUS
&& MP_TOKEN_OP_PLUS + 1 == MP_TOKEN_OP_MINUS
&& MP_TOKEN_OP_MINUS + 1 == MP_TOKEN_OP_STAR
&& MP_TOKEN_OP_STAR + 1 == MP_TOKEN_OP_AT
&& MP_TOKEN_OP_AT + 1 == MP_TOKEN_OP_DBL_SLASH
&& MP_TOKEN_OP_DBL_SLASH + 1 == MP_TOKEN_OP_SLASH
&& MP_TOKEN_OP_SLASH + 1 == MP_TOKEN_OP_PERCENT
&& MP_TOKEN_OP_PERCENT + 1 == MP_TOKEN_OP_DBL_STAR
&& MP_TOKEN_OP_DBL_STAR + 1 == MP_TOKEN_DEL_PIPE_EQUAL
&& MP_TOKEN_DEL_PIPE_EQUAL + 1 == MP_TOKEN_DEL_CARET_EQUAL
&& MP_TOKEN_DEL_CARET_EQUAL + 1 == MP_TOKEN_DEL_AMPERSAND_EQUAL
&& MP_TOKEN_DEL_AMPERSAND_EQUAL + 1 == MP_TOKEN_DEL_DBL_LESS_EQUAL
&& MP_TOKEN_DEL_DBL_LESS_EQUAL + 1 == MP_TOKEN_DEL_DBL_MORE_EQUAL
&& MP_TOKEN_DEL_DBL_MORE_EQUAL + 1 == MP_TOKEN_DEL_PLUS_EQUAL
&& MP_TOKEN_DEL_PLUS_EQUAL + 1 == MP_TOKEN_DEL_MINUS_EQUAL
&& MP_TOKEN_DEL_MINUS_EQUAL + 1 == MP_TOKEN_DEL_STAR_EQUAL
&& MP_TOKEN_DEL_STAR_EQUAL + 1 == MP_TOKEN_DEL_AT_EQUAL
&& MP_TOKEN_DEL_AT_EQUAL + 1 == MP_TOKEN_DEL_DBL_SLASH_EQUAL
&& MP_TOKEN_DEL_DBL_SLASH_EQUAL + 1 == MP_TOKEN_DEL_SLASH_EQUAL
&& MP_TOKEN_DEL_SLASH_EQUAL + 1 == MP_TOKEN_DEL_PERCENT_EQUAL
&& MP_TOKEN_DEL_PERCENT_EQUAL + 1 == MP_TOKEN_DEL_DBL_STAR_EQUAL
&& MP_TOKEN_DEL_DBL_STAR_EQUAL + 1 == MP_TOKEN_DEL_PAREN_OPEN
&& MP_TOKEN_DEL_PAREN_OPEN + 1 == MP_TOKEN_DEL_PAREN_CLOSE
&& MP_TOKEN_DEL_PAREN_CLOSE + 1 == MP_TOKEN_DEL_BRACKET_OPEN
&& MP_TOKEN_DEL_BRACKET_OPEN + 1 == MP_TOKEN_DEL_BRACKET_CLOSE
&& MP_TOKEN_DEL_BRACKET_CLOSE + 1 == MP_TOKEN_DEL_BRACE_OPEN
&& MP_TOKEN_DEL_BRACE_OPEN + 1 == MP_TOKEN_DEL_BRACE_CLOSE
&& MP_TOKEN_DEL_BRACE_CLOSE + 1 == MP_TOKEN_DEL_COMMA
&& MP_TOKEN_DEL_COMMA + 1 == MP_TOKEN_DEL_COLON
&& MP_TOKEN_DEL_COLON + 1 == MP_TOKEN_DEL_PERIOD
&& MP_TOKEN_DEL_PERIOD + 1 == MP_TOKEN_DEL_SEMICOLON
&& MP_TOKEN_DEL_SEMICOLON + 1 == MP_TOKEN_DEL_EQUAL
&& MP_TOKEN_DEL_EQUAL + 1 == MP_TOKEN_DEL_MINUS_MORE,
"MP_TOKEN order changed, so Code::PythonTextArea::TokenColor might need to change too.");
if ((tokenKind >= MP_TOKEN_OP_TILDE && tokenKind <= MP_TOKEN_DEL_DBL_STAR_EQUAL)
|| tokenKind == MP_TOKEN_DEL_EQUAL
|| tokenKind == MP_TOKEN_DEL_MINUS_MORE)
{
return OperatorColor; return OperatorColor;
} }
return Palette::CodeText; return Palette::CodeText;
@@ -53,6 +136,76 @@ static inline size_t TokenLength(mp_lexer_t * lex, const char * tokenPosition) {
return lex->column - lex->tok_column; return lex->column - lex->tok_column;
} }
PythonTextArea::AutocompletionType PythonTextArea::autocompletionType(const char * autocompletionLocation, const char ** autocompletionLocationBeginning, const char ** autocompletionLocationEnd) const {
const char * location = autocompletionLocation != nullptr ? autocompletionLocation : cursorLocation();
const char * beginningOfToken = nullptr;
/* If there is already autocompleting, the cursor must be at the end of an
* identifier. Trying to compute autocompletionType will fail: because of the
* autocompletion text, the cursor seems to be in the middle of an identifier. */
AutocompletionType autocompleteType = isAutocompleting() ? AutocompletionType::EndOfIdentifier : AutocompletionType::NoIdentifier;
if (autocompletionLocationBeginning == nullptr && autocompletionLocationEnd == nullptr) {
return autocompleteType;
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
const char * firstNonSpace = UTF8Helper::BeginningOfWord(m_contentView.editedText(), location);
mp_lexer_t * lex = mp_lexer_new_from_str_len(0, firstNonSpace, UTF8Helper::EndOfWord(location) - firstNonSpace, 0);
const char * tokenStart;
const char * tokenEnd;
_mp_token_kind_t currentTokenKind = lex->tok_kind;
while (currentTokenKind != MP_TOKEN_NEWLINE && currentTokenKind != MP_TOKEN_END) {
tokenStart = firstNonSpace + lex->tok_column - 1;
tokenEnd = tokenStart + TokenLength(lex, tokenStart);
if (location < tokenStart) {
// The location for autocompletion is not in an identifier
assert(autocompleteType == AutocompletionType::NoIdentifier);
break;
}
if (location <= tokenEnd) {
if (currentTokenKind == MP_TOKEN_NAME
|| (currentTokenKind >= MP_TOKEN_KW_FALSE
&& currentTokenKind <= MP_TOKEN_KW_YIELD))
{
/* The location for autocompletion is in the middle or at the end of
* an identifier. */
beginningOfToken = tokenStart;
/* If autocompleteType is already EndOfIdentifier, we are
* autocompleting, so we do not need to update autocompleteType. If we
* recomputed autocompleteType now, we might wrongly think that it is
* MiddleOfIdentifier because of the autocompetion text.
* Example : fin|ally -> the lexer is at the end of "fin", but because
* we are autocompleting with "ally", the lexer thinks the cursor is
* in the middle of an identifier. */
if (autocompleteType != AutocompletionType::EndOfIdentifier) {
autocompleteType = location < tokenEnd ? AutocompletionType::MiddleOfIdentifier : AutocompletionType::EndOfIdentifier;
}
}
break;
}
mp_lexer_to_next(lex);
currentTokenKind = lex->tok_kind;
}
mp_lexer_free(lex);
nlr_pop();
}
if (autocompletionLocationBeginning != nullptr) {
*autocompletionLocationBeginning = beginningOfToken;
}
if (autocompletionLocationEnd != nullptr) {
*autocompletionLocationEnd = location;
}
assert(!isAutocompleting() || autocompleteType == AutocompletionType::EndOfIdentifier);
return autocompleteType;
}
const char * PythonTextArea::ContentView::textToAutocomplete() const {
return UTF8Helper::BeginningOfWord(editedText(), cursorLocation());
}
void PythonTextArea::ContentView::loadSyntaxHighlighter() { void PythonTextArea::ContentView::loadSyntaxHighlighter() {
m_pythonDelegate->initPythonWithUser(this); m_pythonDelegate->initPythonWithUser(this);
} }
@@ -76,23 +229,7 @@ void PythonTextArea::ContentView::clearRect(KDContext * ctx, KDRect rect) const
void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t byteLength, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const { void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char * text, size_t byteLength, int fromColumn, int toColumn, const char * selectionStart, const char * selectionEnd) const {
LOG_DRAW("Drawing \"%.*s\"\n", byteLength, text); LOG_DRAW("Drawing \"%.*s\"\n", byteLength, text);
if (!m_pythonDelegate->isPythonUser(this)) { assert(m_pythonDelegate->isPythonUser(this));
const char * lineStart = UTF8Helper::CodePointAtGlyphOffset(text, fromColumn);
const char * lineEnd = UTF8Helper::CodePointAtGlyphOffset(text, toColumn);
drawStringAt(
ctx,
line,
fromColumn,
lineStart,
minPointer(text + byteLength, lineEnd) - lineStart,
StringColor,
BackgroundColor,
selectionStart,
selectionEnd,
HighlightColor
);
return;
}
/* We're using the MicroPython lexer to do syntax highlighting on a per-line /* We're using the MicroPython lexer to do syntax highlighting on a per-line
* basis. This can work, however the MicroPython lexer won't accept a line * basis. This can work, however the MicroPython lexer won't accept a line
@@ -107,7 +244,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
line, line,
fromColumn, fromColumn,
spacesStart, spacesStart,
minPointer(text + byteLength, firstNonSpace) - spacesStart, std::min(text + byteLength, firstNonSpace) - spacesStart,
StringColor, StringColor,
BackgroundColor, BackgroundColor,
selectionStart, selectionStart,
@@ -118,6 +255,8 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
return; return;
} }
const char * autocompleteStart = m_autocomplete ? m_cursorLocation : nullptr;
nlr_buf_t nlr; nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_lexer_t * lex = mp_lexer_new_from_str_len(0, firstNonSpace, byteLength - (firstNonSpace - text), 0); mp_lexer_t * lex = mp_lexer_new_from_str_len(0, firstNonSpace, byteLength - (firstNonSpace - text), 0);
@@ -135,7 +274,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
line, line,
UTF8Helper::GlyphOffsetAtCodePoint(text, tokenEnd), UTF8Helper::GlyphOffsetAtCodePoint(text, tokenEnd),
tokenEnd, tokenEnd,
minPointer(text + byteLength, tokenFrom) - tokenEnd, std::min(text + byteLength, tokenFrom) - tokenEnd,
StringColor, StringColor,
BackgroundColor, BackgroundColor,
selectionStart, selectionStart,
@@ -144,12 +283,16 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
} }
tokenLength = TokenLength(lex, tokenFrom); tokenLength = TokenLength(lex, tokenFrom);
tokenEnd = tokenFrom + tokenLength; tokenEnd = tokenFrom + tokenLength;
// If the token is being autocompleted, use DefaultColor
KDColor color = (tokenFrom <= autocompleteStart && autocompleteStart < tokenEnd) ? Palette::CodeText : TokenColor(lex->tok_kind);
LOG_DRAW("Draw \"%.*s\" for token %d\n", tokenLength, tokenFrom, lex->tok_kind); LOG_DRAW("Draw \"%.*s\" for token %d\n", tokenLength, tokenFrom, lex->tok_kind);
drawStringAt(ctx, line, drawStringAt(ctx, line,
UTF8Helper::GlyphOffsetAtCodePoint(text, tokenFrom), UTF8Helper::GlyphOffsetAtCodePoint(text, tokenFrom),
tokenFrom, tokenFrom,
tokenLength, tokenLength,
TokenColor(lex->tok_kind), color,
BackgroundColor, BackgroundColor,
selectionStart, selectionStart,
selectionEnd, selectionEnd,
@@ -161,6 +304,7 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
tokenFrom += tokenLength; tokenFrom += tokenLength;
// Even if the token is being autocompleted, use CommentColor
if (tokenFrom < text + byteLength) { if (tokenFrom < text + byteLength) {
LOG_DRAW("Draw comment \"%.*s\" from %d\n", byteLength - (tokenFrom - text), firstNonSpace, tokenFrom); LOG_DRAW("Draw comment \"%.*s\" from %d\n", byteLength - (tokenFrom - text), firstNonSpace, tokenFrom);
drawStringAt(ctx, line, drawStringAt(ctx, line,
@@ -177,6 +321,22 @@ void PythonTextArea::ContentView::drawLine(KDContext * ctx, int line, const char
mp_lexer_free(lex); mp_lexer_free(lex);
nlr_pop(); nlr_pop();
} }
// Redraw the autocompleted word in the right color
if (m_autocomplete && autocompleteStart >= text && autocompleteStart < text + byteLength) {
assert(m_autocompletionEnd != nullptr && m_autocompletionEnd > autocompleteStart);
drawStringAt(
ctx,
line,
UTF8Helper::GlyphOffsetAtCodePoint(text, autocompleteStart),
autocompleteStart,
std::min(text + byteLength, m_autocompletionEnd) - autocompleteStart,
AutocompleteColor,
BackgroundColor,
nullptr,
nullptr,
HighlightColor);
}
} }
KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position, bool includeFollowingLines) const { KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position, bool includeFollowingLines) const {
@@ -194,4 +354,158 @@ KDRect PythonTextArea::ContentView::dirtyRectFromPosition(const char * position,
); );
} }
bool PythonTextArea::handleEvent(Ion::Events::Event event) {
if (m_contentView.isAutocompleting()) {
// Handle event with autocompletion
if (event == Ion::Events::Right
|| event == Ion::Events::ShiftRight
|| event == Ion::Events::OK)
{
m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false);
acceptAutocompletion(event != Ion::Events::ShiftRight);
if (event != Ion::Events::ShiftRight) {
// Do not process the event more
scrollToCursor();
return true;
}
} else if (event == Ion::Events::Toolbox
|| event == Ion::Events::Var
|| event == Ion::Events::Shift
|| event == Ion::Events::Alpha
|| event == Ion::Events::OnOff)
{
} else if(event == Ion::Events::Up
|| event == Ion::Events::Down)
{
cycleAutocompletion(event == Ion::Events::Down);
return true;
} else {
removeAutocompletion();
m_contentView.reloadRectFromPosition(m_contentView.cursorLocation(), false);
if (event == Ion::Events::Back) {
// Do not process the event more
return true;
}
}
}
bool result = TextArea::handleEvent(event);
if (event == Ion::Events::Backspace && !m_contentView.isAutocompleting() && selectionIsEmpty()) {
/* We want to add autocompletion when we are editing a word (after adding or
* deleting text). So if nothing is selected, we add the autocompletion if
* the event is backspace, as autocompletion has already been added if the
* event added text, in handleEventWithText. */
addAutocompletion();
}
return result;
}
bool PythonTextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
if (*text == 0) {
return false;
}
if (m_contentView.isAutocompleting()) {
removeAutocompletion();
}
bool result = TextArea::handleEventWithText(text, indentation, forceCursorRightOfText);
addAutocompletion();
return result;
}
void PythonTextArea::removeAutocompletion() {
assert(m_contentView.isAutocompleting());
removeAutocompletionText();
m_contentView.setAutocompleting(false);
}
void PythonTextArea::removeAutocompletionText() {
assert(m_contentView.isAutocompleting());
assert(m_contentView.autocompletionEnd() != nullptr);
const char * autocompleteStart = m_contentView.cursorLocation();
const char * autocompleteEnd = m_contentView.autocompletionEnd();
assert(autocompleteEnd != nullptr && autocompleteEnd > autocompleteStart);
m_contentView.removeText(autocompleteStart, autocompleteEnd);
}
void PythonTextArea::addAutocompletion() {
assert(!m_contentView.isAutocompleting());
const char * autocompletionTokenBeginning = nullptr;
const char * autocompletionLocation = const_cast<char *>(cursorLocation());
m_autocompletionResultIndex = 0;
if (autocompletionType(autocompletionLocation, &autocompletionTokenBeginning) != AutocompletionType::EndOfIdentifier) {
// The cursor is not at the end of an identifier.
return;
}
// First load variables and functions that complete the textToAutocomplete
const int scriptIndex = m_contentView.pythonDelegate()->menuController()->editedScriptIndex();
m_contentView.pythonDelegate()->variableBoxController()->loadFunctionsAndVariables(scriptIndex, autocompletionTokenBeginning, autocompletionLocation - autocompletionTokenBeginning);
if (addAutocompletionTextAtIndex(0)) {
m_contentView.setAutocompleting(true);
}
}
bool PythonTextArea::addAutocompletionTextAtIndex(int nextIndex, int * currentIndexToUpdate) {
// The variable box should be loaded at this point
const char * autocompletionTokenBeginning = nullptr;
const char * autocompletionLocation = const_cast<char *>(cursorLocation());
AutocompletionType type = autocompletionType(autocompletionLocation, &autocompletionTokenBeginning); // Done to get autocompletionTokenBeginning
assert(type == AutocompletionType::EndOfIdentifier);
(void)type; // Silence warnings
VariableBoxController * varBox = m_contentView.pythonDelegate()->variableBoxController();
int textToInsertLength = 0;
bool addParentheses = false;
const char * textToInsert = varBox->autocompletionAlternativeAtIndex(autocompletionLocation - autocompletionTokenBeginning, &textToInsertLength, &addParentheses, nextIndex, currentIndexToUpdate);
if (textToInsert == nullptr) {
return false;
}
if (textToInsertLength > 0) {
// Try to insert the text (this might fail if the buffer is full)
if (!m_contentView.insertTextAtLocation(textToInsert, const_cast<char *>(autocompletionLocation), textToInsertLength)) {
return false;
}
autocompletionLocation += textToInsertLength;
m_contentView.setAutocompletionEnd(autocompletionLocation);
}
// Try to insert the parentheses if needed
const char * parentheses = ScriptNodeCell::k_parentheses;
constexpr int parenthesesLength = 2;
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<char *>(autocompletionLocation), parenthesesLength)) {
m_contentView.setAutocompleting(true);
m_contentView.setAutocompletionEnd(autocompletionLocation + parenthesesLength);
}
return true;
}
void PythonTextArea::cycleAutocompletion(bool downwards) {
assert(m_contentView.isAutocompleting());
removeAutocompletionText();
addAutocompletionTextAtIndex(m_autocompletionResultIndex + (downwards ? 1 : -1), &m_autocompletionResultIndex);
}
void PythonTextArea::acceptAutocompletion(bool moveCursorToEndOfAutocompletion) {
assert(m_contentView.isAutocompleting());
// Save the cursor location
const char * previousCursorLocation = cursorLocation();
removeAutocompletion();
m_contentView.pythonDelegate()->variableBoxController()->setSender(this);
m_contentView.pythonDelegate()->variableBoxController()->insertAutocompletionResultAtIndex(m_autocompletionResultIndex);
// insertAutocompletionResultAtIndex already added the autocompletion
// If we did not want to move the cursor, restore its position.
if (!moveCursorToEndOfAutocompletion) {
setCursorLocation(previousCursorLocation);
}
}
} }

View File

@@ -9,21 +9,46 @@ class App;
class PythonTextArea : public TextArea { class PythonTextArea : public TextArea {
public: public:
enum class AutocompletionType : uint8_t {
EndOfIdentifier,
MiddleOfIdentifier,
NoIdentifier
};
PythonTextArea(Responder * parentResponder, App * pythonDelegate, const KDFont * font) : PythonTextArea(Responder * parentResponder, App * pythonDelegate, const KDFont * font) :
TextArea(parentResponder, &m_contentView, font), TextArea(parentResponder, &m_contentView, font),
m_contentView(pythonDelegate, font) m_contentView(pythonDelegate, font),
m_autocompletionResultIndex(0)
{ {
} }
void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); } void loadSyntaxHighlighter() { m_contentView.loadSyntaxHighlighter(); }
void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); } void unloadSyntaxHighlighter() { m_contentView.unloadSyntaxHighlighter(); }
bool handleEvent(Ion::Events::Event event) override;
bool handleEventWithText(const char * text, bool indentation = false, bool forceCursorRightOfText = 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. */
AutocompletionType autocompletionType(const char * autocompletionLocation = nullptr, const char ** autocompletionLocationBeginning = nullptr, const char ** autocompletionLocationEnd = nullptr) const;
bool isAutocompleting() const { return m_contentView.isAutocompleting(); }
protected: protected:
class ContentView : public TextArea::ContentView { class ContentView : public TextArea::ContentView {
public: public:
ContentView(App * pythonDelegate, const KDFont * font) : ContentView(App * pythonDelegate, const KDFont * font) :
TextArea::ContentView(font), TextArea::ContentView(font),
m_pythonDelegate(pythonDelegate) m_pythonDelegate(pythonDelegate),
m_autocomplete(false),
m_autocompletionEnd(nullptr)
{ {
} }
App * pythonDelegate() { return m_pythonDelegate; }
void setAutocompleting(bool autocomplete) { m_autocomplete = autocomplete; }
bool isAutocompleting() const { return m_autocomplete; }
const char * autocompletionEnd() const { assert(m_autocomplete); return m_autocompletionEnd; }
void setAutocompletionEnd(const char * end) { m_autocompletionEnd = end; }
const char * textToAutocomplete() const;
void loadSyntaxHighlighter(); void loadSyntaxHighlighter();
void unloadSyntaxHighlighter(); void unloadSyntaxHighlighter();
void clearRect(KDContext * ctx, KDRect rect) const override; void clearRect(KDContext * ctx, KDRect rect) const override;
@@ -31,10 +56,19 @@ protected:
KDRect dirtyRectFromPosition(const char * position, bool includeFollowingLines) const override; KDRect dirtyRectFromPosition(const char * position, bool includeFollowingLines) const override;
private: private:
App * m_pythonDelegate; App * m_pythonDelegate;
bool m_autocomplete;
const char * m_autocompletionEnd;
}; };
private: private:
void removeAutocompletion();
void removeAutocompletionText(); // Just removes the suggested text, not the autocompletion mode
void addAutocompletion();
bool addAutocompletionTextAtIndex(int nextIndex, int * currentIndexToUpdate = nullptr); // Assumes the var box is already loaded
void cycleAutocompletion(bool downwards);
void acceptAutocompletion(bool moveCursorToEndOfAutocompletion);
const ContentView * nonEditableContentView() const override { return &m_contentView; } const ContentView * nonEditableContentView() const override { return &m_contentView; }
ContentView m_contentView; ContentView m_contentView;
int m_autocompletionResultIndex;
}; };
} }

View File

@@ -120,7 +120,18 @@ const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText) ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false)
}; };
const ToolboxMessageTree TurtleModuleChildren[] = { const ToolboxMessageTree TurtleModuleChildren[] = {
@@ -141,21 +152,23 @@ const ToolboxMessageTree TurtleModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPenup, I18n::Message::PythonTurtlePenup, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPenup, I18n::Message::PythonTurtlePenup, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPensize, I18n::Message::PythonTurtlePensize), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPensize, I18n::Message::PythonTurtlePensize),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandIsdown, I18n::Message::PythonTurtleIsdown, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandIsdown, I18n::Message::PythonTurtleIsdown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWrite, I18n::Message::PythonTurtleWrite),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColor, I18n::Message::PythonTurtleColor, false, I18n::Message::PythonTurtleCommandColorWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColor, I18n::Message::PythonTurtleColor),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColorMode, I18n::Message::PythonTurtleColorMode),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRed, I18n::Message::PythonTurtleRed, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandYellow, I18n::Message::PythonTurtleYellow, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBrown, I18n::Message::PythonTurtleBrown, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWhite, I18n::Message::PythonTurtleWhite, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPink, I18n::Message::PythonTurtlePink, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandOrange, I18n::Message::PythonTurtleOrange, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false) ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false)
}; };
const ToolboxMessageTree RandomModuleChildren[] = { const ToolboxMessageTree RandomModuleChildren[] = {
@@ -277,14 +290,15 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBackward, I18n::Message::PythonTurtleBackward), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBackward, I18n::Message::PythonTurtleBackward),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBin, I18n::Message::PythonBin), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBin, I18n::Message::PythonBin),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlack, I18n::Message::PythonColorBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBlue, I18n::Message::PythonColorBlue, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBrown, I18n::Message::PythonTurtleBrown, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorBrown, I18n::Message::PythonColorBrown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCeil, I18n::Message::PythonCeil), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCeil, I18n::Message::PythonCeil),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandCircle, I18n::Message::PythonTurtleCircle), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandCircle, I18n::Message::PythonTurtleCircle),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCmathFunction, I18n::Message::PythonCmathFunction, false, I18n::Message::PythonCommandCmathFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCmathFunction, I18n::Message::PythonCmathFunction, false, I18n::Message::PythonCommandCmathFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandColorMode, I18n::Message::PythonTurtleColorMode),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandComplex, I18n::Message::PythonComplex), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandComplex, I18n::Message::PythonComplex),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCopySign, I18n::Message::PythonCopySign), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCopySign, I18n::Message::PythonCopySign),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCos, I18n::Message::PythonCos), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCos, I18n::Message::PythonCos),
@@ -317,8 +331,8 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGoto, I18n::Message::PythonTurtleGoto), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGoto, I18n::Message::PythonTurtleGoto),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGreen, I18n::Message::PythonColorGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGrey, I18n::Message::PythonColorGrey, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHeading, I18n::Message::PythonTurtleHeading, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHeading, I18n::Message::PythonTurtleHeading, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHex, I18n::Message::PythonHex), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHex, I18n::Message::PythonHex),
@@ -364,19 +378,19 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandModf, I18n::Message::PythonModf), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandModf, I18n::Message::PythonModf),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMonotonic, I18n::Message::PythonMonotonic, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMonotonic, I18n::Message::PythonMonotonic, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandOct, I18n::Message::PythonOct), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandOct, I18n::Message::PythonOct),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandOrange, I18n::Message::PythonTurtleOrange, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorOrange, I18n::Message::PythonColorOrange, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPendown, I18n::Message::PythonTurtlePendown, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPendown, I18n::Message::PythonTurtlePendown, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPenup, I18n::Message::PythonTurtlePenup, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPenup, I18n::Message::PythonTurtlePenup, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPensize, I18n::Message::PythonTurtlePensize), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPensize, I18n::Message::PythonTurtlePensize),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPhase, I18n::Message::PythonPhase), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPhase, I18n::Message::PythonPhase),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandConstantPi, I18n::Message::PythonConstantPi, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandConstantPi, I18n::Message::PythonConstantPi, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPink, I18n::Message::PythonTurtlePink, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPink, I18n::Message::PythonColorPink, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorPurple, I18n::Message::PythonColorPurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRadians, I18n::Message::PythonRadians), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRadians, I18n::Message::PythonRadians),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false),
@@ -385,7 +399,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStartStop, I18n::Message::PythonRangeStartStop), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStartStop, I18n::Message::PythonRangeStartStop),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStop, I18n::Message::PythonRangeStop), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRangeStop, I18n::Message::PythonRangeStop),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRect, I18n::Message::PythonRect), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRect, I18n::Message::PythonRect),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRed, I18n::Message::PythonTurtleRed, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorRed, I18n::Message::PythonColorRed, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound),
@@ -409,8 +423,9 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTrunc, I18n::Message::PythonTrunc), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTrunc, I18n::Message::PythonTrunc),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWhite, I18n::Message::PythonTurtleWhite, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorWhite, I18n::Message::PythonColorWhite, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandYellow, I18n::Message::PythonTurtleYellow, false), ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandWrite, I18n::Message::PythonTurtleWrite),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorYellow, I18n::Message::PythonColorYellow, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImag, I18n::Message::PythonImag, false, I18n::Message::PythonCommandImagWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImag, I18n::Message::PythonImag, false, I18n::Message::PythonCommandImagWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReal, I18n::Message::PythonReal, false, I18n::Message::PythonCommandRealWithoutArg) ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReal, I18n::Message::PythonReal, false, I18n::Message::PythonCommandRealWithoutArg)
}; };
@@ -420,11 +435,39 @@ const ToolboxMessageTree functionsChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReturn, I18n::Message::Default) ToolboxMessageTree::Leaf(I18n::Message::PythonCommandReturn, I18n::Message::Default)
}; };
const ToolboxMessageTree fileChildren[] {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileOpen, I18n::Message::PythonFileOpen, false, I18n::Message::PythonCommandFileOpenWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileClose, I18n::Message::PythonFileClose, false, I18n::Message::PythonCommandFileCloseWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileClosed, I18n::Message::PythonFileClosed, false, I18n::Message::PythonCommandFileClosedWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileMode, I18n::Message::PythonFileMode, false, I18n::Message::PythonCommandFileModeWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileName, I18n::Message::PythonFileName, false, I18n::Message::PythonCommandFileNameWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileRead, I18n::Message::PythonFileRead, false, I18n::Message::PythonCommandFileReadWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileReadable, I18n::Message::PythonFileReadable, false, I18n::Message::PythonCommandFileReadableWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileReadline, I18n::Message::PythonFileReadline, false, I18n::Message::PythonCommandFileReadlineWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileReadlines, I18n::Message::PythonFileReadlines, false, I18n::Message::PythonCommandFileReadlinesWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileSeek, I18n::Message::PythonFileSeek, false, I18n::Message::PythonCommandFileSeekWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileSeekable, I18n::Message::PythonFileSeekable, false, I18n::Message::PythonCommandFileSeekableWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileTell, I18n::Message::PythonFileTell, false, I18n::Message::PythonCommandFileTellWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileTruncate, I18n::Message::PythonFileTruncate, false, I18n::Message::PythonCommandFileTruncateWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileWrite, I18n::Message::PythonFileWrite, false, I18n::Message::PythonCommandFileWriteWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileWritable, I18n::Message::PythonFileWritable, false, I18n::Message::PythonCommandFileWritableWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFileWritelines, I18n::Message::PythonFileWritelines, false, I18n::Message::PythonCommandFileWritelinesWithoutArg),
};
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),
};
const ToolboxMessageTree menu[] = { const ToolboxMessageTree menu[] = {
ToolboxMessageTree::Node(I18n::Message::LoopsAndTests, loopsAndTestsChildren), ToolboxMessageTree::Node(I18n::Message::LoopsAndTests, loopsAndTestsChildren),
ToolboxMessageTree::Node(I18n::Message::Modules, modulesChildren), ToolboxMessageTree::Node(I18n::Message::Modules, modulesChildren),
ToolboxMessageTree::Node(I18n::Message::Catalog, catalogChildren), ToolboxMessageTree::Node(I18n::Message::Catalog, catalogChildren),
ToolboxMessageTree::Node(I18n::Message::Functions, functionsChildren) ToolboxMessageTree::Node(I18n::Message::Functions, functionsChildren),
ToolboxMessageTree::Node(I18n::Message::Files, fileChildren),
ToolboxMessageTree::Node(I18n::Message::Exceptions, exceptionsChildren)
}; };
const ToolboxMessageTree toolboxModel = ToolboxMessageTree::Node(I18n::Message::Toolbox, menu); const ToolboxMessageTree toolboxModel = ToolboxMessageTree::Node(I18n::Message::Toolbox, menu);
@@ -435,6 +478,20 @@ PythonToolbox::PythonToolbox() :
{ {
} }
const ToolboxMessageTree * PythonToolbox::moduleChildren(const char * name, int * numberOfNodes) const {
for (ToolboxMessageTree t : modulesChildren) {
if (strcmp(I18n::translate(t.label()), name) == 0) {
const int childrenCount = t.numberOfChildren();
if (numberOfNodes != nullptr) {
*numberOfNodes = childrenCount;
}
assert(childrenCount > 0);
return static_cast<const ToolboxMessageTree *>(t.childAtIndex(0));
}
}
return nullptr;
}
bool PythonToolbox::handleEvent(Ion::Events::Event event) { bool PythonToolbox::handleEvent(Ion::Events::Event event) {
if (Toolbox::handleEvent(event)) { if (Toolbox::handleEvent(event)) {
return true; return true;
@@ -450,7 +507,7 @@ bool PythonToolbox::handleEvent(Ion::Events::Event event) {
} }
KDCoordinate PythonToolbox::rowHeight(int j) { KDCoordinate PythonToolbox::rowHeight(int j) {
if (typeAtLocation(0, j) == Toolbox::LeafCellType && m_messageTreeModel->label() == I18n::Message::IfStatementMenu) { 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 /* 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' * 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 * chars. This is very costly and ruins the speed performance when
@@ -460,7 +517,7 @@ KDCoordinate PythonToolbox::rowHeight(int j) {
* We thus decided to compute the real height only for the ifStatement * 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 * children of the toolbox, which is the only menu that has special height
* rows. */ * rows. */
const ToolboxMessageTree * messageTree = static_cast<const ToolboxMessageTree *>(m_messageTreeModel->children(j)); const ToolboxMessageTree * messageTree = static_cast<const ToolboxMessageTree *>(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)); return k_font->stringSize(I18n::translate(messageTree->label())).height() + 2*Metric::TableCellVerticalMargin + (messageTree->text() == I18n::Message::Default ? 0 : Toolbox::rowHeight(j));
} }
return Toolbox::rowHeight(j); return Toolbox::rowHeight(j);
@@ -468,7 +525,7 @@ KDCoordinate PythonToolbox::rowHeight(int j) {
bool PythonToolbox::selectLeaf(int selectedRow) { bool PythonToolbox::selectLeaf(int selectedRow) {
m_selectableTableView.deselectTable(); m_selectableTableView.deselectTable();
ToolboxMessageTree * node = (ToolboxMessageTree *)m_messageTreeModel->children(selectedRow); ToolboxMessageTree * node = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(selectedRow);
const char * editedText = I18n::translate(node->insertedText()); const char * editedText = I18n::translate(node->insertedText());
// strippedEditedText array needs to be in the same scope as editedText // strippedEditedText array needs to be in the same scope as editedText
char strippedEditedText[k_maxMessageSize]; char strippedEditedText[k_maxMessageSize];
@@ -509,7 +566,7 @@ void PythonToolbox::scrollToLetter(char letter) {
char lowerLetter = tolower(letter); char lowerLetter = tolower(letter);
int index = -1; int index = -1;
for (int i = 0; i < m_messageTreeModel->numberOfChildren(); i++) { for (int i = 0; i < m_messageTreeModel->numberOfChildren(); i++) {
char l = tolower(I18n::translate(m_messageTreeModel->children(i)->label())[0]); char l = tolower(I18n::translate(m_messageTreeModel->childAtIndex(i)->label())[0]);
if (l == lowerLetter) { if (l == lowerLetter) {
index = i; index = i;
break; break;

View File

@@ -10,7 +10,11 @@ namespace Code {
class PythonToolbox : public Toolbox { class PythonToolbox : public Toolbox {
public: public:
// PythonToolbox
PythonToolbox(); PythonToolbox();
const ToolboxMessageTree * moduleChildren(const char * name, int * numberOfNodes) const;
// Toolbox
bool handleEvent(Ion::Events::Event event) override; bool handleEvent(Ion::Events::Event event) override;
const ToolboxMessageTree * rootModel() const override; const ToolboxMessageTree * rootModel() const override;
protected: protected:

View File

@@ -65,22 +65,54 @@ bool Script::nameCompliant(const char * name) {
return false; return false;
} }
bool Script::importationStatus() const { uint8_t * StatusFromData(Script::Data d) {
assert(!isNull()); return const_cast<uint8_t *>(static_cast<const uint8_t *>(d.buffer));
Data d = value();
return (((char *)d.buffer)[0] == 1);
} }
void Script::toggleImportationStatus() { bool Script::autoImportationStatus() const {
return getStatutBit(k_autoImportationStatusMask);
}
void Script::toggleAutoimportationStatus() {
assert(!isNull());
Data d = value(); Data d = value();
((char *)d.buffer)[0] = (((char *)d.buffer)[0] == 1 ? 0 : 1); *StatusFromData(d) ^= k_autoImportationStatusMask;
setValue(d); setValue(d);
} }
const char * Script::scriptContent() const { const char * Script::content() const {
Data d = value();
return ((const char *)d.buffer) + StatusSize();
}
bool Script::fetchedFromConsole() const {
return getStatutBit(k_fetchedFromConsoleMask);
}
void Script::setFetchedFromConsole(bool fetched) {
setStatutBit(k_fetchedFromConsoleMask, k_fetchedFromConsoleOffset, fetched);
}
bool Script::fetchedForVariableBox() const {
return getStatutBit(k_fetchedForVariableBoxMask);
}
void Script::setFetchedForVariableBox(bool fetched) {
setStatutBit(k_fetchedForVariableBoxMask, k_fetchedForVariableBoxOffset, fetched);
}
bool Script::getStatutBit(uint8_t mask) const {
assert(!isNull()); assert(!isNull());
Data d = value(); Data d = value();
return (const char *)d.buffer + k_importationStatusSize; return ((*StatusFromData(d)) & mask) != 0;
}
void Script::setStatutBit(uint8_t mask, uint8_t offset, bool statusBit) {
assert(!isNull());
Data d = value();
uint8_t * status = StatusFromData(d);
*status = ((*status) & ~mask) | (static_cast<uint8_t>(statusBit) << offset); //TODO Create and use a bit operations library
setValue(d);
} }
} }

View File

@@ -5,16 +5,36 @@
namespace Code { namespace Code {
/* Record : | Total Size | Name | Body | /* Record: | Size | Name | Body |
* Script: | AutoImportationStatus | Content |*/ * Script: | | | Status | Content |
*
*
* |FetchedForVariableBoxBit
* Status is one byte long: xxxxxxxx
* ^ ^
* FetchedFromConsoleBit AutoImportationBit
*
* AutoImportationBit is 1 if the script should be auto imported when the
* console opens.
*
* FetchedFromConsoleBit is 1 if its content has been fetched from the console,
* so we can retrieve the correct variables afterwards in the variable box.
*
* FetchedForVariableBoxBit is used to prevent circular importation problems,
* such as scriptA importing scriptB, which imports scriptA. Once we get the
* variables from a script to put them in the variable box, we switch the bit to
* 1 and won't reload it afterwards. */
class Script : public Ion::Storage::Record { class Script : public Ion::Storage::Record {
private: private:
// Default script names are chosen between script1 and script99 // Default script names are chosen between script1 and script99
static constexpr int k_maxNumberOfDefaultScriptNames = 99; static constexpr int k_maxNumberOfDefaultScriptNames = 99;
static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max static constexpr int k_defaultScriptNameNumberMaxSize = 2; // Numbers from 1 to 99 have 2 digits max
// See the comment at the beginning of the file
static constexpr size_t k_statusSize = 1;
public: public:
static constexpr size_t k_importationStatusSize = 1;
static constexpr int k_defaultScriptNameMaxSize = 6 + k_defaultScriptNameNumberMaxSize + 1; static constexpr int k_defaultScriptNameMaxSize = 6 + k_defaultScriptNameNumberMaxSize + 1;
/* 6 = strlen("script") /* 6 = strlen("script")
* k_defaultScriptNameNumberMaxSize = maxLength of integers between 1 and 99 * k_defaultScriptNameNumberMaxSize = maxLength of integers between 1 and 99
@@ -22,11 +42,29 @@ public:
static bool DefaultName(char buffer[], size_t bufferSize); static bool DefaultName(char buffer[], size_t bufferSize);
static bool nameCompliant(const char * name); static bool nameCompliant(const char * name);
static constexpr size_t StatusSize() { return k_statusSize; }
Script(Ion::Storage::Record r) : Record(r) {}
bool importationStatus() const; Script(Ion::Storage::Record r = Ion::Storage::Record()) : Record(r) {}
void toggleImportationStatus(); bool autoImportationStatus() const;
const char * scriptContent() const; void toggleAutoimportationStatus();
const char * content() const;
/* Fetched status */
bool fetchedFromConsole() const;
void setFetchedFromConsole(bool fetched);
bool fetchedForVariableBox() const;
void setFetchedForVariableBox(bool fetched);
private:
static constexpr uint8_t k_autoImportationStatusMask = 0b1;
static constexpr uint8_t k_fetchedForVariableBoxOffset = 7;
static constexpr uint8_t k_fetchedFromConsoleOffset = 6;
static constexpr uint8_t k_fetchedForVariableBoxMask = 0b1 << k_fetchedForVariableBoxOffset;
static constexpr uint8_t k_fetchedFromConsoleMask = 0b1 << k_fetchedFromConsoleOffset;
bool getStatutBit(uint8_t offset) const;
void setStatutBit(uint8_t mask, uint8_t offset, bool value);
}; };
} }

View File

@@ -1,33 +1,35 @@
#ifndef CODE_SCRIPT_NODE_H #ifndef CODE_SCRIPT_NODE_H
#define CODE_SCRIPT_NODE_H #define CODE_SCRIPT_NODE_H
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
namespace Code { namespace Code {
class ScriptNode { class ScriptNode {
public: public:
enum class Type { enum class Type : bool {
Function = 0, WithoutParentheses,
Variable = 1 WithParentheses
}; };
ScriptNode() : ScriptNode(Type type = Type::WithoutParentheses, const char * name = nullptr, int nameLength = -1, const char * nodeSourceName = nullptr, const char * description = nullptr) :
m_type(Type::Function), m_name(nullptr), m_scriptIndex(0) {} m_type(type),
static ScriptNode FunctionNode(const char * name, uint16_t scriptIndex) { m_name(name),
return ScriptNode(Type::Function, name, scriptIndex); m_nodeSourceName(nodeSourceName),
} m_description(description),
static ScriptNode VariableNode(const char * name, uint16_t scriptIndex) { m_nameLength(nameLength)
return ScriptNode(Type::Variable, name, scriptIndex); {}
}
Type type() const { return m_type; } Type type() const { return m_type; }
const char * name() const { return m_name; } const char * name() const { return m_name; }
uint16_t scriptIndex() const { return m_scriptIndex; } int nameLength() const { return static_cast<int>(m_nameLength); }
const char * nodeSourceName() const { return m_nodeSourceName; }
const char * description() const { return m_description; }
private: private:
ScriptNode(Type type, const char * name, uint16_t scriptIndex) :
m_type(type), m_name(name), m_scriptIndex(scriptIndex) {}
Type m_type; Type m_type;
const char * m_name; const char * m_name;
uint16_t m_scriptIndex; const char * m_nodeSourceName;
const char * m_description;
size_t m_nameLength;
}; };
} }

View File

@@ -7,47 +7,51 @@ namespace Code {
constexpr char ScriptNodeCell::k_parentheses[]; constexpr char ScriptNodeCell::k_parentheses[];
constexpr char ScriptNodeCell::k_parenthesesWithEmpty[]; constexpr char ScriptNodeCell::k_parenthesesWithEmpty[];
ScriptNodeCell::ScriptNodeView::ScriptNodeView() :
HighlightCell(),
m_scriptNode(nullptr),
m_scriptStore(nullptr)
{
}
void ScriptNodeCell::ScriptNodeView::setScriptNode(ScriptNode * scriptNode) {
m_scriptNode = scriptNode;
}
void ScriptNodeCell::ScriptNodeView::setScriptStore(ScriptStore * scriptStore) {
m_scriptStore = scriptStore;
}
void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) const { void ScriptNodeCell::ScriptNodeView::drawRect(KDContext * ctx, KDRect rect) const {
ctx->drawString(m_scriptNode->name(), KDPoint(0, Metric::TableCellVerticalMargin), k_font, Palette::CodeText, isHighlighted()? Palette::CodeBackgroundSelected : Palette::CodeBackground); const KDColor backgroundColor = isHighlighted()? Palette::CodeBackgroundSelected : Palette::CodeBackground;
KDSize nameSize = k_font->stringSize(m_scriptNode->name());
if (m_scriptNode->type() == ScriptNode::Type::Function) { // If it exists, draw the description name.
ctx->drawString(ScriptNodeCell::k_parentheses, KDPoint(nameSize.width(), Metric::TableCellVerticalMargin), k_font, Palette::CodeText, isHighlighted()? Palette::CodeBackgroundSelected : Palette::CodeBackground); const char * descriptionName = m_scriptNode->description();
if (descriptionName != nullptr) {
ctx->drawString(descriptionName, KDPoint(0, m_frame.height() - k_bottomMargin - k_font->glyphSize().height()), k_font, Palette::GreyDark, backgroundColor);
}
// Draw the node name
const char * nodeName = m_scriptNode->name();
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);
// 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);
}
/* If it exists, draw the source name. If it did not fit, we would have put
* nullptr at the node creation. */
const char * sourceName = m_scriptNode->nodeSourceName();
if (sourceName != nullptr) {
KDSize sourceNameSize = k_font->stringSize(sourceName);
ctx->drawString(sourceName, KDPoint(m_frame.width() - sourceNameSize.width(), nodeNameY), k_font, Palette::CodeText, backgroundColor);
} }
ctx->drawString(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName(), KDPoint(0, Metric::TableCellVerticalMargin + nameSize.height() + k_verticalMargin), k_font, Palette::SecondaryText, isHighlighted()? Palette::CodeBackgroundSelected : Palette::CodeBackground);
} }
KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const { KDSize ScriptNodeCell::ScriptNodeView::minimalSizeForOptimalDisplay() const {
if (m_scriptNode->name() == nullptr) { if (m_scriptNode->name() == nullptr) {
return KDSizeZero; return KDSizeZero;
} }
KDSize size1 = k_font->stringSize(m_scriptNode->name()); return KDSize(
KDSize size2 = k_font->stringSize(m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName()); k_optimalWidth,
KDSize size3 = KDSizeZero; m_scriptNode->description() == nullptr ? k_simpleItemHeight : k_complexItemHeight);
if (m_scriptNode->type() == ScriptNode::Type::Function) {
size3 = k_font->stringSize(ScriptNodeCell::k_parentheses);
}
return KDSize(size1.width() + size3.width() > size2.width() ? size1.width() + size3.width() : size2.width(), Metric::TableCellVerticalMargin + size1.width() + k_verticalMargin + size2.width());
} }
ScriptNodeCell::ScriptNodeCell() : bool ScriptNodeCell::CanDisplayNameAndSource(int nameLength, const char * source) {
TableCell(), if (source == nullptr) {
m_scriptNodeView() return true;
{ }
assert(nameLength > 0);
const KDFont * font = ScriptNodeView::k_font;
return font->glyphSize().width()*(nameLength + 1) + font->stringSize(source).width() <= ScriptNodeView::k_optimalWidth; // + 1 for the separating space
} }
void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) { void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) {
@@ -55,10 +59,6 @@ void ScriptNodeCell::setScriptNode(ScriptNode * scriptNode) {
reloadCell(); reloadCell();
} }
void ScriptNodeCell::setScriptStore(ScriptStore * scriptStore) {
m_scriptNodeView.setScriptStore(scriptStore);
}
void ScriptNodeCell::setHighlighted(bool highlight) { void ScriptNodeCell::setHighlighted(bool highlight) {
TableCell::setHighlighted(highlight); TableCell::setHighlighted(highlight);
m_scriptNodeView.setHighlighted(highlight); m_scriptNodeView.setHighlighted(highlight);

View File

@@ -10,9 +10,18 @@ namespace Code {
class ScriptNodeCell : public TableCell { class ScriptNodeCell : public TableCell {
public: public:
ScriptNodeCell(); static_assert('\x11' == UCodePointEmpty, "Unicode error");
constexpr static char k_parentheses[] = "()";
constexpr static char k_parenthesesWithEmpty[] = "(\x11)";
constexpr static KDCoordinate k_simpleItemHeight = 27;
constexpr static KDCoordinate k_complexItemHeight = 42;
ScriptNodeCell() :
TableCell(),
m_scriptNodeView()
{}
void setScriptNode(ScriptNode * node); void setScriptNode(ScriptNode * node);
void setScriptStore(ScriptStore * scriptStore); static bool CanDisplayNameAndSource(int nameLength, const char * source);
/* TableCell */ /* TableCell */
View * labelView() const override { return const_cast<View *>(static_cast<const View *>(&m_scriptNodeView)); } View * labelView() const override { return const_cast<View *>(static_cast<const View *>(&m_scriptNodeView)); }
@@ -22,26 +31,25 @@ public:
void reloadCell() override; void reloadCell() override;
const char * text() const override { return m_scriptNodeView.text(); } const char * text() const override { return m_scriptNodeView.text(); }
static_assert('\x11' == UCodePointEmpty, "Unicode error");
constexpr static char k_parentheses[] = "()";
constexpr static char k_parenthesesWithEmpty[] = "(\x11)";
protected: protected:
class ScriptNodeView : public HighlightCell { class ScriptNodeView : public HighlightCell {
public: public:
ScriptNodeView(); constexpr static const KDFont * k_font = KDFont::SmallFont;
void setScriptNode(ScriptNode * scriptNode); constexpr static KDCoordinate k_optimalWidth = Ion::Display::Width - Metric::PopUpLeftMargin - Metric::PopUpRightMargin;
void setScriptStore(ScriptStore * scriptStore); ScriptNodeView() :
HighlightCell(),
m_scriptNode(nullptr)
{}
void setScriptNode(ScriptNode * node) { m_scriptNode = node; }
void drawRect(KDContext * ctx, KDRect rect) const override; void drawRect(KDContext * ctx, KDRect rect) const override;
virtual KDSize minimalSizeForOptimalDisplay() const override; virtual KDSize minimalSizeForOptimalDisplay() const override;
const char * text() const override { const char * text() const override {
return m_scriptStore->scriptAtIndex(m_scriptNode->scriptIndex()).fullName(); return m_scriptNode->description();
} }
private: private:
constexpr static const KDFont * k_font = KDFont::SmallFont; constexpr static KDCoordinate k_bottomMargin = 5;
constexpr static KDCoordinate k_verticalMargin = 7; constexpr static KDCoordinate k_topMargin = k_bottomMargin + k_separatorThickness;
ScriptNode * m_scriptNode; ScriptNode * m_scriptNode;
ScriptStore * m_scriptStore;
}; };
ScriptNodeView m_scriptNodeView; ScriptNodeView m_scriptNodeView;
}; };

View File

@@ -1,5 +1,6 @@
#include "script_parameter_controller.h" #include "script_parameter_controller.h"
#include "menu_controller.h" #include "menu_controller.h"
#include <poincare/integer.h>
namespace Code { namespace Code {
@@ -11,6 +12,7 @@ ScriptParameterController::ScriptParameterController(Responder * parentResponder
m_autoImportScript(I18n::Message::AutoImportScript), m_autoImportScript(I18n::Message::AutoImportScript),
m_deleteScript(I18n::Message::DeleteScript), m_deleteScript(I18n::Message::DeleteScript),
m_duplicateScript(I18n::Message::DuplicateScript), m_duplicateScript(I18n::Message::DuplicateScript),
m_size(I18n::Message::ScriptSize),
m_selectableTableView(this), m_selectableTableView(this),
m_script(Ion::Storage::Record()), m_script(Ion::Storage::Record()),
m_menuController(menuController) m_menuController(menuController)
@@ -43,21 +45,27 @@ bool ScriptParameterController::handleEvent(Ion::Events::Event event) {
m_menuController->renameSelectedScript(); m_menuController->renameSelectedScript();
return true; return true;
case 2: case 2:
m_script.toggleImportationStatus(); m_script.toggleAutoimportationStatus();
m_selectableTableView.reloadData(); m_selectableTableView.reloadData();
m_menuController->reloadConsole(); m_menuController->reloadConsole();
Container::activeApp()->setFirstResponder(&m_selectableTableView); Container::activeApp()->setFirstResponder(&m_selectableTableView);
return true; return true;
case 3: case 3:{
dismissScriptParameterController(); MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)m_selectableTableView.selectedCell();
m_menuController->deleteScript(s); m_sizedisplaypercent = !m_sizedisplaypercent;
m_menuController->reloadConsole(); GetScriptSize(myCell);
return true; return true;
}
case 4: case 4:
dismissScriptParameterController(); dismissScriptParameterController();
m_menuController->duplicateScript(s); m_menuController->duplicateScript(s);
m_menuController->reloadConsole(); m_menuController->reloadConsole();
return true; return true;
case 5:
dismissScriptParameterController();
m_menuController->deleteScript(s);
m_menuController->reloadConsole();
return true;
default: default:
assert(false); assert(false);
return false; return false;
@@ -80,14 +88,43 @@ void ScriptParameterController::didBecomeFirstResponder() {
HighlightCell * ScriptParameterController::reusableCell(int index) { HighlightCell * ScriptParameterController::reusableCell(int index) {
assert(index >= 0); assert(index >= 0);
assert(index < k_totalNumberOfCell); assert(index < k_totalNumberOfCell);
HighlightCell * cells[] = {&m_executeScript, &m_renameScript, &m_autoImportScript, &m_deleteScript, &m_duplicateScript}; HighlightCell * cells[] = {&m_executeScript, &m_renameScript, &m_autoImportScript, &m_size, &m_duplicateScript, &m_deleteScript};
return cells[index]; return cells[index];
} }
void ScriptParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) { void ScriptParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) {
if (cell == &m_autoImportScript) { if (cell == &m_autoImportScript) {
SwitchView * switchView = (SwitchView *)m_autoImportScript.accessoryView(); SwitchView * switchView = (SwitchView *)m_autoImportScript.accessoryView();
switchView->setState(m_script.importationStatus()); switchView->setState(m_script.autoImportationStatus());
} else if (cell == &m_size) {
MessageTableCellWithBuffer * myCell = (MessageTableCellWithBuffer *)cell;
GetScriptSize(myCell);
myCell->setAccessoryFont(KDFont::SmallFont);
myCell->setAccessoryTextColor(Palette::SecondaryText);
}
}
void ScriptParameterController::GetScriptSize(MessageTableCellWithBuffer* myCell){
if(m_sizedisplaypercent){
char size[18];
int sizelen = Poincare::Integer((int)m_script.value().size).serialize(size, 6);
size[sizelen] = ' ';
size[sizelen+1] = 'o';
size[sizelen+2] = ' ';
size[sizelen+3] = '/';
size[sizelen+4] = ' ';
int sizelen2 = Poincare::Integer((int)Ion::Storage::k_storageSize).serialize(size+sizelen+5, 6) + sizelen + 5;
size[sizelen2] = ' ';
size[sizelen2+1] = 'o';
size[sizelen2+2] = '\0';
myCell->setAccessoryText(size);
}else{
char size[18];
int sizelen = Poincare::Integer((int)(((float)((int)m_script.value().size)/((int)Ion::Storage::k_storageSize)) * 100.f)).serialize(size, 3);
size[sizelen] = ' ';
size[sizelen+1] = '%';
size[sizelen+2] = '\0';
myCell->setAccessoryText(size);
} }
} }

View File

@@ -31,7 +31,7 @@ public:
void willDisplayCellForIndex(HighlightCell * cell, int index) override; void willDisplayCellForIndex(HighlightCell * cell, int index) override;
private: private:
constexpr static int k_totalNumberOfCell = 5; constexpr static int k_totalNumberOfCell = 6;
StackViewController * stackViewController(); StackViewController * stackViewController();
I18n::Message m_pageTitle; I18n::Message m_pageTitle;
MessageTableCell m_executeScript; MessageTableCell m_executeScript;
@@ -39,9 +39,12 @@ private:
MessageTableCellWithSwitch m_autoImportScript; MessageTableCellWithSwitch m_autoImportScript;
MessageTableCell m_deleteScript; MessageTableCell m_deleteScript;
MessageTableCell m_duplicateScript; MessageTableCell m_duplicateScript;
MessageTableCellWithBuffer m_size;
void GetScriptSize(MessageTableCellWithBuffer* myCell);
SelectableTableView m_selectableTableView; SelectableTableView m_selectableTableView;
Script m_script; Script m_script;
MenuController * m_menuController; MenuController * m_menuController;
bool m_sizedisplaypercent = false;
}; };
} }

View File

@@ -1,23 +1,14 @@
#include "script_store.h" #include "script_store.h"
#include "string.h"
#include <stddef.h>
extern "C" {
#include "py/lexer.h"
#include "py/nlr.h"
}
namespace Code { namespace Code {
constexpr char ScriptStore::k_scriptExtension[]; constexpr char ScriptStore::k_scriptExtension[];
bool ScriptStore::ScriptNameIsFree(const char * baseName) { bool ScriptStore::ScriptNameIsFree(const char * baseName) {
return Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(baseName, k_scriptExtension).isNull(); return ScriptBaseNamed(baseName).isNull();
} }
ScriptStore::ScriptStore() ScriptStore::ScriptStore() {
{
addScriptFromTemplate(ScriptTemplate::Squares()); addScriptFromTemplate(ScriptTemplate::Squares());
addScriptFromTemplate(ScriptTemplate::Parabola()); addScriptFromTemplate(ScriptTemplate::Parabola());
addScriptFromTemplate(ScriptTemplate::Mandelbrot()); addScriptFromTemplate(ScriptTemplate::Mandelbrot());
@@ -34,118 +25,39 @@ bool ScriptStore::isFull() {
return Ion::Storage::sharedStorage()->availableSize() < k_fullFreeSpaceSizeLimit; return Ion::Storage::sharedStorage()->availableSize() < k_fullFreeSpaceSizeLimit;
} }
void ScriptStore::scanScriptsForFunctionsAndVariables(void * context, ScanCallback storeFunction, ScanCallback storeVariable) { const char * ScriptStore::contentOfScript(const char * name, bool markAsFetched) {
for (int scriptIndex = 0; scriptIndex < numberOfScripts(); scriptIndex++) { Script script = ScriptNamed(name);
// Handle lexer or parser errors with nlr.
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
const char * scriptContent = scriptAtIndex(scriptIndex).scriptContent();
if (scriptContent == nullptr) {
continue;
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(0, scriptContent, strlen(scriptContent), false);
mp_parse_tree_t parseTree = mp_parse(lex, MP_PARSE_FILE_INPUT);
mp_parse_node_t pn = parseTree.root;
if (!MP_PARSE_NODE_IS_STRUCT(pn)) {
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
// The script is only a single function definition.
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) == k_functionDefinitionParseNodeStructKind) {
const char * id = structID(pns);
if (id == nullptr) {
continue;
}
storeFunction(context, id, scriptIndex);
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
// The script is only a single global variable definition.
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) == k_expressionStatementParseNodeStructKind) {
const char * id = structID(pns);
if (id == nullptr) {
continue;
}
storeVariable(context, id, scriptIndex);
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(pns))) != k_fileInput2ParseNodeStructKind) {
// The script node is not of type "file_input_2", thus it will not have main
// structures of the wanted type.
mp_parse_tree_clear(&parseTree);
nlr_pop();
continue;
}
// Count the number of structs in child nodes.
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];
if (MP_PARSE_NODE_IS_STRUCT(child)) {
mp_parse_node_struct_t *child_pns = (mp_parse_node_struct_t*)(child);
if (((uint)(MP_PARSE_NODE_STRUCT_KIND(child_pns))) == k_functionDefinitionParseNodeStructKind) {
const char * id = structID(child_pns);
if (id == nullptr) {
continue;
}
storeFunction(context, id, scriptIndex);
} else if (((uint)(MP_PARSE_NODE_STRUCT_KIND(child_pns))) == k_expressionStatementParseNodeStructKind) {
const char * id = structID(child_pns);
if (id == nullptr) {
continue;
}
storeVariable(context, id, scriptIndex);
}
}
}
mp_parse_tree_clear(&parseTree);
nlr_pop();
}
}
}
const char * ScriptStore::contentOfScript(const char * name) {
Script script = scriptNamed(name);
if (script.isNull()) { if (script.isNull()) {
return nullptr; return nullptr;
} }
return script.scriptContent(); if (markAsFetched) {
script.setFetchedFromConsole(true);
}
return script.content();
}
void ScriptStore::clearVariableBoxFetchInformation() {
// TODO optimize fetches
const int scriptsCount = numberOfScripts();
for (int i = 0; i < scriptsCount; i++) {
scriptAtIndex(i).setFetchedForVariableBox(false);
}
}
void ScriptStore::clearConsoleFetchInformation() {
// TODO optimize fetches
const int scriptsCount = numberOfScripts();
for (int i = 0; i < scriptsCount; i++) {
scriptAtIndex(i).setFetchedFromConsole(false);
}
} }
Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * scriptTemplate) { Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * scriptTemplate) {
size_t valueSize = strlen(scriptTemplate->content())+1+1;// scriptcontent size + 1 char for the importation status size_t valueSize = Script::StatusSize() + strlen(scriptTemplate->content()) + 1; // (auto importation status + content fetched status) + scriptcontent size + null-terminating char
assert(Script::nameCompliant(scriptTemplate->name())); assert(Script::nameCompliant(scriptTemplate->name()));
Script::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithFullName(scriptTemplate->name(), scriptTemplate->value(), valueSize); Script::ErrorStatus err = Ion::Storage::sharedStorage()->createRecordWithFullName(scriptTemplate->name(), scriptTemplate->value(), valueSize);
assert(err != Script::ErrorStatus::NonCompliantName); assert(err != Script::ErrorStatus::NonCompliantName);
return err; return err;
} }
const char * ScriptStore::structID(mp_parse_node_struct_t *structNode) {
// Find the id child node, which stores the struct's name
size_t childNodesCount = MP_PARSE_NODE_STRUCT_NUM_NODES(structNode);
if (childNodesCount < 1) {
return nullptr;
}
mp_parse_node_t child = structNode->nodes[0];
if (MP_PARSE_NODE_IS_LEAF(child)
&& MP_PARSE_NODE_LEAF_KIND(child) == MP_PARSE_NODE_ID)
{
uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(child);
return qstr_str(arg);
}
return nullptr;
}
} }

View File

@@ -23,8 +23,11 @@ public:
Script scriptAtIndex(int index) { Script scriptAtIndex(int index) {
return Script(Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(k_scriptExtension, index)); return Script(Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(k_scriptExtension, index));
} }
Script scriptNamed(const char * name) { static Script ScriptNamed(const char * fullName) {
return Script(Ion::Storage::sharedStorage()->recordNamed(name)); return Script(Ion::Storage::sharedStorage()->recordNamed(fullName));
}
static Script ScriptBaseNamed(const char * baseName) {
return Script(Ion::Storage::sharedStorage()->recordBaseNamedWithExtension(baseName, k_scriptExtension));
} }
int numberOfScripts() { int numberOfScripts() {
return Ion::Storage::sharedStorage()->numberOfRecordsWithExtension(k_scriptExtension); return Ion::Storage::sharedStorage()->numberOfRecordsWithExtension(k_scriptExtension);
@@ -35,12 +38,10 @@ public:
void deleteAllScripts(); void deleteAllScripts();
bool isFull(); bool isFull();
/* Provide scripts content information */
typedef void (* ScanCallback)(void * context, const char * p, int n);
void scanScriptsForFunctionsAndVariables(void * context, ScanCallback storeFunction,ScanCallback storeVariable);
/* MicroPython::ScriptProvider */ /* MicroPython::ScriptProvider */
const char * contentOfScript(const char * name) override; const char * contentOfScript(const char * name, bool markAsFetched) override;
void clearVariableBoxFetchInformation();
void clearConsoleFetchInformation();
Ion::Storage::Record::ErrorStatus addScriptFromTemplate(const ScriptTemplate * scriptTemplate); Ion::Storage::Record::ErrorStatus addScriptFromTemplate(const ScriptTemplate * scriptTemplate);
private: private:
@@ -51,10 +52,6 @@ private:
* importation status (1 char), the default content "from math import *\n" * importation status (1 char), the default content "from math import *\n"
* (20 char) and 10 char of free space. */ * (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; static constexpr int k_fullFreeSpaceSizeLimit = sizeof(Ion::Storage::record_size_t)+Script::k_defaultScriptNameMaxSize+k_scriptExtensionLength+1+20+10;
static constexpr size_t k_fileInput2ParseNodeStructKind = 1;
static constexpr size_t k_functionDefinitionParseNodeStructKind = 3;
static constexpr size_t k_expressionStatementParseNodeStructKind = 5;
const char * structID(mp_parse_node_struct_t *structNode);
}; };
} }

Some files were not shown because too many files have changed in this diff Show More