mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
Merge branch 'master' of github.com:numworks/epsilon into f7
This commit is contained in:
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Epsilon is not working like it should? Let us know!
|
||||
labels: 'bug'
|
||||
|
||||
---
|
||||
#### Describe the bug
|
||||
A clear and concise description of what the bug is. Please describe a **single** bug per issue. Feel free to create multiple issues though!
|
||||
|
||||
#### Screenshots
|
||||
Please provide at least one screenshot of the issue happening. This is by far the best way to quickly show any issue! To attach a screenshot, just go to our [online simulator](https://www.numworks.com/simulator), navigate to reproduce your issue, and click the "screenshot" button. Then drag'n'drop the file here!
|
||||
|
||||
#### To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to the '...' app
|
||||
2. Type '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
#### Expected behavior
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
#### Environment
|
||||
- Epsilon version (Settings > About > Software version).
|
||||
- The platform(s) on which the problem happens: online simulator, actual device, etc...
|
||||
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for an improvement of Epsilon
|
||||
labels: 'enhancement'
|
||||
|
||||
---
|
||||
#### Problem you'd like to fix
|
||||
Is your feature request related to a problem? Please provide a clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
Please describe a **single** improvement per issue. Feel free to open multiple issues though!
|
||||
|
||||
#### Screenshots
|
||||
If possible, please attach a screenshot. You can go on our [online simulator](https://www.numworks.com/simulator), use the screenshot button, and drag'n'drop the file here.
|
||||
|
||||
#### Describe the solution you'd like
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
#### Describe alternatives you've considered
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
#### Additional context
|
||||
Add any other context or screenshots about the feature request here.
|
||||
50
.gitignore
vendored
50
.gitignore
vendored
@@ -1,52 +1,4 @@
|
||||
# No objects files.
|
||||
*.o
|
||||
*.elf
|
||||
*.exe
|
||||
|
||||
# No dependency files
|
||||
*.d
|
||||
|
||||
# No lex / yacc generated files.
|
||||
poincare/src/expression_lexer.cpp
|
||||
poincare/src/expression_lexer.hpp
|
||||
poincare/src/expression_parser.cpp
|
||||
poincare/src/expression_parser.hpp
|
||||
|
||||
# No rulegen generated files
|
||||
poincare/src/simplification/rulegen/rules_tokens.h
|
||||
poincare/src/simplification/rulegen/rules_lexer.cpp
|
||||
poincare/src/simplification/rulegen/rules_parser.cpp
|
||||
poincare/src/simplification/rulegen/rulegen
|
||||
poincare/src/simplification/demo_ruleset.h
|
||||
|
||||
# Font related generated files.
|
||||
kandinsky/fonts/rasterizer
|
||||
kandinsky/src/font_large.cpp
|
||||
kandinsky/src/font_small.cpp
|
||||
|
||||
# No i18n headers
|
||||
apps/i18n.h
|
||||
apps/i18n.cpp
|
||||
|
||||
# No PicView generated files
|
||||
apps/picview/image.raw
|
||||
apps/picview/image.c
|
||||
|
||||
# No AST file
|
||||
*.ast
|
||||
*.ast.json
|
||||
|
||||
# Quiz output
|
||||
quiz/src/symbols.c
|
||||
|
||||
# No generated icon & font files
|
||||
*_icon.cpp
|
||||
*_icon.h
|
||||
*_font.c
|
||||
*_font.h
|
||||
|
||||
# Ignore inliner binary
|
||||
escher/image/inliner
|
||||
|
||||
# Ignore generated qtsrdefs file
|
||||
python/port/genhdr/qstrdefs.generated.h
|
||||
build
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
global:
|
||||
- MAKEFLAGS="-j 2"
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
@@ -19,4 +23,4 @@ os: linux
|
||||
script:
|
||||
- set -e
|
||||
- make clean && make epsilon.$EXT test.$EXT
|
||||
- if [ "$PLATFORM" = "blackbox" ]; then ./test.$EXT; PLATFORM=blackbox make integration_tests; fi
|
||||
- if [ "$PLATFORM" = "blackbox" ]; then build/blackbox/test.$EXT; PLATFORM=blackbox make integration_tests; fi
|
||||
|
||||
123
Makefile
123
Makefile
@@ -1,6 +1,27 @@
|
||||
include build/config.mak
|
||||
include scripts/config.mak
|
||||
|
||||
default: epsilon.$(EXE)
|
||||
# Disable default Make rules
|
||||
.SUFFIXES:
|
||||
|
||||
object_for = $(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(basename $(1))))
|
||||
|
||||
default: $(BUILD_DIR)/epsilon.$(EXE)
|
||||
|
||||
# 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_for
|
||||
$(addprefix $$(BUILD_DIR)/,$(strip $(2))): $(strip $(3)) | $$$$(@D)/.
|
||||
@ echo "$(shell printf "%-8s" $(strip $(1)))$$(@:$$(BUILD_DIR)/%=%)"
|
||||
$(Q) $(4)
|
||||
ifeq ($(strip $(5)),with_local_version)
|
||||
$(addprefix $$(BUILD_DIR)/,$(strip $(2))): $(addprefix $$(BUILD_DIR)/,$(strip $(3)))
|
||||
@ echo "$(shell printf "%-8s" $(strip $(1)))$$(@:$$(BUILD_DIR)/%=%)"
|
||||
$(Q) $(4)
|
||||
endif
|
||||
endef
|
||||
|
||||
.PHONY: info
|
||||
info:
|
||||
@@ -10,16 +31,24 @@ info:
|
||||
@echo "EPSILON_APPS = $(EPSILON_APPS)"
|
||||
@echo "EPSILON_I18N = $(EPSILON_I18N)"
|
||||
|
||||
# Each sub-Makefile can either add objects to the $(objs) variable or define a
|
||||
# new executable target. The $(objs) variable lists the objects that will be
|
||||
# linked to every executable being generated. Each Makefile is also responsible
|
||||
# for keeping the $(product) variable updated. This variable lists all files
|
||||
# that could be generated during the build and that needs to be cleaned up
|
||||
# afterwards.
|
||||
# Since we're building out-of-tree, we need to make sure the output directories
|
||||
# are created, otherwise the receipes will fail (e.g. gcc will fail to create
|
||||
# "output/foo/bar.o" because the directory "output/foo" doesn't exist).
|
||||
# We need to mark those directories as precious, otherwise Make will try to get
|
||||
# rid of them upon completion (and fail, since those folders won't be empty).
|
||||
.PRECIOUS: $(BUILD_DIR)/. $(BUILD_DIR)%/.
|
||||
$(BUILD_DIR)/.:
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
$(BUILD_DIR)%/.:
|
||||
$(Q) mkdir -p $(dir $@)
|
||||
|
||||
products :=
|
||||
# To make objects dependent on their directory, we need a second expansion
|
||||
.SECONDEXPANSION:
|
||||
|
||||
# Each sub-Makefile can either add sources to the $(src) variable or define a
|
||||
# new executable target. The $(src) variable lists the sources that will be
|
||||
# built and linked to every executable being generated.
|
||||
|
||||
# Library Makefiles
|
||||
ifeq ($(USE_LIBA),0)
|
||||
include liba/Makefile.bridge
|
||||
else
|
||||
@@ -34,43 +63,61 @@ include python/Makefile
|
||||
include escher/Makefile
|
||||
# Executable Makefiles
|
||||
include apps/Makefile
|
||||
include build/struct_layout/Makefile
|
||||
include build/scenario/Makefile
|
||||
include scripts/struct_layout/Makefile
|
||||
include scripts/scenario/Makefile
|
||||
include quiz/Makefile # Quiz needs to be included at the end
|
||||
|
||||
products += $(objs)
|
||||
|
||||
all_objs = $(filter %.o, $(products))
|
||||
dependencies = $(all_objs:.o=.d)
|
||||
-include $(dependencies)
|
||||
products += $(dependencies)
|
||||
|
||||
$(all_objs): $(generated_headers)
|
||||
|
||||
epsilon.$(EXE): $(objs)
|
||||
test.$(EXE): $(objs)
|
||||
|
||||
objs = $(call object_for,$(src))
|
||||
.SECONDARY: $(objs)
|
||||
%.$(EXE):
|
||||
@echo "LD $@"
|
||||
$(Q) $(LD) $^ $(LDFLAGS) -o $@
|
||||
|
||||
%.o: %.c
|
||||
@echo "CC $@"
|
||||
$(Q) $(CC) $(SFLAGS) $(CFLAGS) -c $< -o $@
|
||||
# Load source-based dependencies
|
||||
# Compilers can generate Makefiles that states the dependencies of a given
|
||||
# objet to other source and headers. This serve no purpose for a clean build,
|
||||
# but allows correct yet optimal incremental builds.
|
||||
-include $(objs:.o=.d)
|
||||
|
||||
%.o: %.s
|
||||
@echo "AS $@"
|
||||
$(Q) $(CC) $(SFLAGS) -c $< -o $@
|
||||
# Define rules for executables
|
||||
# Those can be built directly with make executable.exe as a shortcut. They also
|
||||
# depends on $(objs)
|
||||
|
||||
%.o: %.cpp
|
||||
@echo "CXX $@"
|
||||
$(Q) $(CXX) $(SFLAGS) $(CXXFLAGS) -c $< -o $@
|
||||
executables = epsilon test flasher
|
||||
|
||||
define rules_for_executable
|
||||
$$(BUILD_DIR)/$(1).$$(EXE): $$(objs)
|
||||
.PHONY: $(1).$$(EXE)
|
||||
$(1).$$(EXE): $$(BUILD_DIR)/$(1).$$(EXE)
|
||||
endef
|
||||
|
||||
$(foreach executable,$(executables),$(eval $(call rules_for_executable,$(executable))))
|
||||
|
||||
# Define standard compilation rules
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
AS, %.o, %.s, \
|
||||
$$(CC) $$(SFLAGS) -c $$< -o $$@ \
|
||||
))
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
CC, %.o, %.c, \
|
||||
$$(CC) $$(SFLAGS) $$(CFLAGS) -c $$< -o $$@, \
|
||||
with_local_version \
|
||||
))
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
CXX, %.o, %.cpp, \
|
||||
$$(CC) $$(SFLAGS) $$(CXXFLAGS) -c $$< -o $$@, \
|
||||
with_local_version \
|
||||
))
|
||||
|
||||
$(eval $(call rule_for, \
|
||||
LD, %.$$(EXE), , \
|
||||
$$(LD) $$^ $$(LDFLAGS) -o $$@ \
|
||||
))
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "CLEAN"
|
||||
$(Q) rm -f $(products)
|
||||
$(Q) rm -rf $(BUILD_DIR)
|
||||
|
||||
.PHONY: cowsay_%
|
||||
cowsay_%:
|
||||
@@ -86,4 +133,4 @@ cowsay_%:
|
||||
.PHONY: clena
|
||||
clena: cowsay_CLENA clean
|
||||
|
||||
-include build/targets.$(PLATFORM).mak
|
||||
-include scripts/targets.$(PLATFORM).mak
|
||||
|
||||
@@ -10,26 +10,24 @@ apps =
|
||||
# (path to the apps header).
|
||||
$(foreach i,${EPSILON_APPS},$(eval include apps/$(i)/Makefile))
|
||||
|
||||
app_objs += $(addprefix apps/,\
|
||||
apps_container.o\
|
||||
apps_container_storage.o\
|
||||
apps_window.o\
|
||||
battery_timer.o\
|
||||
battery_view.o\
|
||||
constant.o\
|
||||
backlight_dimming_timer.o\
|
||||
empty_battery_window.o\
|
||||
exam_pop_up_controller.o\
|
||||
global_preferences.o\
|
||||
i18n.o\
|
||||
lock_view.o\
|
||||
main.o\
|
||||
math_toolbox.o\
|
||||
shift_alpha_lock_view.o\
|
||||
suspend_timer.o\
|
||||
title_bar_view.o\
|
||||
variable_box_controller.o\
|
||||
variable_box_empty_controller.o\
|
||||
app_src += $(addprefix apps/,\
|
||||
apps_container.cpp \
|
||||
apps_container_storage.cpp \
|
||||
apps_window.cpp \
|
||||
backlight_dimming_timer.cpp \
|
||||
battery_timer.cpp \
|
||||
battery_view.cpp \
|
||||
constant.cpp \
|
||||
empty_battery_window.cpp \
|
||||
exam_pop_up_controller.cpp \
|
||||
global_preferences.cpp \
|
||||
lock_view.cpp \
|
||||
math_toolbox.cpp \
|
||||
shift_alpha_lock_view.cpp \
|
||||
suspend_timer.cpp \
|
||||
title_bar_view.cpp \
|
||||
variable_box_controller.cpp \
|
||||
variable_box_empty_controller.cpp \
|
||||
)
|
||||
|
||||
snapshots_declaration = $(foreach i,$(apps),$(i)::Snapshot m_snapshot$(subst :,,$(i))Snapshot;)
|
||||
@@ -40,8 +38,12 @@ snapshots_count = $(words $(apps))
|
||||
snapshot_includes = $(foreach i,$(app_headers),-include $(i) )
|
||||
epsilon_app_names = '$(foreach i,${EPSILON_APPS},"$(i)", )'
|
||||
|
||||
apps/apps_container_storage.o apps/main.o: CXXFLAGS += $(snapshot_includes) -DAPPS_CONTAINER_APPS_DECLARATION="$(apps_declaration)" -DAPPS_CONTAINER_SNAPSHOT_DECLARATIONS="$(snapshots_declaration)" -DAPPS_CONTAINER_SNAPSHOT_CONSTRUCTORS="$(snapshots_construction)" -DAPPS_CONTAINER_SNAPSHOT_LIST="$(snapshots_list)" -DAPPS_CONTAINER_SNAPSHOT_COUNT=$(snapshots_count) -DEPSILON_APPS_NAMES=$(epsilon_app_names)
|
||||
$(call object_for,apps/apps_container_storage.cpp apps/main.cpp): CXXFLAGS += $(snapshot_includes) -DAPPS_CONTAINER_APPS_DECLARATION="$(apps_declaration)" -DAPPS_CONTAINER_SNAPSHOT_DECLARATIONS="$(snapshots_declaration)" -DAPPS_CONTAINER_SNAPSHOT_CONSTRUCTORS="$(snapshots_construction)" -DAPPS_CONTAINER_SNAPSHOT_LIST="$(snapshots_list)" -DAPPS_CONTAINER_SNAPSHOT_COUNT=$(snapshots_count) -DEPSILON_APPS_NAMES=$(epsilon_app_names)
|
||||
|
||||
# I18n file generation
|
||||
|
||||
# The header is refered to as <apps/i18n.h> so make sure it's findable this way
|
||||
SFLAGS += -I$(BUILD_DIR)
|
||||
|
||||
i18n_files += $(addprefix apps/language_,$(addsuffix .universal.i18n, $(EPSILON_I18N)))
|
||||
i18n_files += $(addprefix apps/,\
|
||||
@@ -63,32 +65,35 @@ i18n_files += $(addprefix apps/,\
|
||||
variables.pt.i18n\
|
||||
)
|
||||
|
||||
apps/i18n.h: apps/i18n.cpp
|
||||
apps/i18n.cpp: $(i18n_files)
|
||||
@echo "I18N $@"
|
||||
$(Q) $(PYTHON) apps/i18n.py --header $(subst .cpp,.h,$@) --implementation $@ --locales $(EPSILON_I18N) --files $^
|
||||
$(eval $(call rule_for, \
|
||||
I18N, \
|
||||
apps/i18n.cpp, \
|
||||
$(i18n_files), \
|
||||
$$(PYTHON) apps/i18n.py --header $$(subst .cpp,.h,$$@) --implementation $$@ --locales $$(EPSILON_I18N) --files $$^ \
|
||||
))
|
||||
|
||||
$(app_objs): apps/i18n.h
|
||||
$(BUILD_DIR)/apps/i18n.h: $(BUILD_DIR)/apps/i18n.cpp
|
||||
|
||||
products += apps/i18n.h apps/i18n.cpp
|
||||
# Handle PNG files
|
||||
|
||||
app_images += apps/exam_icon.png
|
||||
$(eval $(call depends_on_image,apps/title_bar_view.cpp,apps/exam_icon.png))
|
||||
|
||||
# Tracking which source file uses which image is painful. But we need to ensure
|
||||
# that a .png file has been inlined before building any source file that uses
|
||||
# said image (because it will expect the ".h" file to be there).
|
||||
# As a shortcut, we simply say that every app file depends on every image. In
|
||||
# practice, this forces all the images to be before the app.
|
||||
# Handle epsilon-only sources
|
||||
# Other executables may want to do their own i18n and main. That's the case for
|
||||
# the test runner. Let's add those files to a specific epsilon-only src. When
|
||||
# building apps/i18n.o, the extension doesn't really matter since it'll be
|
||||
# processed by the object_for function.
|
||||
|
||||
app_image_objs := $(app_images:.png=.o)
|
||||
.SECONDARY: $(app_images:.png=.cpp)
|
||||
$(app_objs): $(app_image_objs)
|
||||
epsilon_src += $(addprefix apps/, \
|
||||
main.cpp \
|
||||
i18n.py \
|
||||
)
|
||||
|
||||
epsilon.$(EXE): $(app_objs) $(app_image_objs)
|
||||
all_app_src = $(app_src) $(epsilon_src)
|
||||
|
||||
TO_REMOVE := apps/main.o apps/i18n.o
|
||||
TMP := $(app_objs) $(app_image_objs)
|
||||
VAR := $(filter-out $(TO_REMOVE), $(TMP))
|
||||
test.$(EXE): $(VAR)
|
||||
$(call object_for,$(all_app_src)): $(BUILD_DIR)/apps/i18n.h
|
||||
$(call object_for,$(all_app_src)): $(BUILD_DIR)/python/port/genhdr/qstrdefs.generated.h
|
||||
|
||||
products += epsilon.$(EXE) $(app_objs) $(call INLINER_PRODUCTS,$(app_images))
|
||||
$(BUILD_DIR)/epsilon.$(EXE): $(call object_for,$(epsilon_src))
|
||||
|
||||
src += $(app_src)
|
||||
|
||||
@@ -84,7 +84,7 @@ AppsContainer::AppsContainer() :
|
||||
* We just remove the circuit breaker for now.
|
||||
* TODO: Put the Poincare circuit breaker back on epsilon's web emulator */
|
||||
#else
|
||||
Poincare::Expression::setCircuitBreaker(AppsContainer::poincareCircuitBreaker);
|
||||
Poincare::Expression::SetCircuitBreaker(AppsContainer::poincareCircuitBreaker);
|
||||
#endif
|
||||
Ion::Storage::sharedStorage()->setDelegate(this);
|
||||
}
|
||||
@@ -152,18 +152,19 @@ bool AppsContainer::dispatchEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::USBEnumeration) {
|
||||
if (Ion::USB::isPlugged()) {
|
||||
App::Snapshot * activeSnapshot = (activeApp() == nullptr ? appSnapshotAtIndex(0) : activeApp()->snapshot());
|
||||
if (activeApp() == nullptr || activeApp()->prepareForExit()) {
|
||||
if (switchTo(usbConnectedAppSnapshot())) {
|
||||
/* Just after a software update, the battery timer does not have time to
|
||||
* fire before the calculator enters DFU mode. As the DFU mode blocks the
|
||||
* event loop, we update the battery state "manually" here. */
|
||||
updateBatteryState();
|
||||
switchTo(usbConnectedAppSnapshot());
|
||||
Ion::USB::DFU();
|
||||
switchTo(activeSnapshot);
|
||||
bool switched = switchTo(activeSnapshot);
|
||||
assert(switched);
|
||||
(void) switched; // Silence compilation warning about unused variable.
|
||||
didProcessEvent = true;
|
||||
} else {
|
||||
/* activeApp()->prepareForExit() returned false, which means that the
|
||||
* app needs another event loop to prepare for being switched off.
|
||||
/* We could not switch apps, which means that the current app needs
|
||||
* another event loop to prepare for being switched off.
|
||||
* Discard the current enumeration interruption.
|
||||
* The USB host tries a few times in a row to enumerate the device, so
|
||||
* hopefully the device will get another enumeration event soon and this
|
||||
@@ -222,8 +223,7 @@ bool AppsContainer::processEvent(Ion::Events::Event event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void AppsContainer::switchTo(App::Snapshot * snapshot) {
|
||||
assert(activeApp() == nullptr || activeApp()->prepareForExit());
|
||||
bool AppsContainer::switchTo(App::Snapshot * snapshot) {
|
||||
if (activeApp() && snapshot != activeApp()->snapshot()) {
|
||||
resetShiftAlphaStatus();
|
||||
}
|
||||
@@ -235,7 +235,7 @@ void AppsContainer::switchTo(App::Snapshot * snapshot) {
|
||||
if (snapshot) {
|
||||
m_window.setTitle(snapshot->descriptor()->upperName());
|
||||
}
|
||||
Container::switchTo(snapshot);
|
||||
return Container::switchTo(snapshot);
|
||||
}
|
||||
|
||||
void AppsContainer::run() {
|
||||
@@ -252,15 +252,14 @@ void AppsContainer::run() {
|
||||
/* Normal execution. The exception checkpoint must be created before
|
||||
* switching to the first app, because the first app might create nodes on
|
||||
* the pool. */
|
||||
bool switched =
|
||||
#if EPSILON_ONBOARDING_APP
|
||||
switchTo(onBoardingAppSnapshot());
|
||||
switchTo(onBoardingAppSnapshot());
|
||||
#else
|
||||
if (numberOfApps() == 2) {
|
||||
switchTo(appSnapshotAtIndex(1));
|
||||
} else {
|
||||
switchTo(appSnapshotAtIndex(0));
|
||||
}
|
||||
switchTo(appSnapshotAtIndex(numberOfApps() == 2 ? 1 : 0));
|
||||
#endif
|
||||
assert(switched);
|
||||
(void) switched; // Silence compilation warning about unused variable.
|
||||
} else {
|
||||
// Exception
|
||||
if (activeApp() != nullptr) {
|
||||
@@ -277,7 +276,9 @@ void AppsContainer::run() {
|
||||
* history here, we will be stuck outside the calculation app. */
|
||||
activeApp()->snapshot()->reset();
|
||||
}
|
||||
switchTo(appSnapshotAtIndex(0));
|
||||
bool switched = switchTo(appSnapshotAtIndex(0));
|
||||
assert(switched);
|
||||
(void) switched; // Silence compilation warning about unused variable.
|
||||
Poincare::Tidy();
|
||||
activeApp()->displayWarning(I18n::Message::PoolMemoryFull1, I18n::Message::PoolMemoryFull2, true);
|
||||
}
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
#include "backlight_dimming_timer.h"
|
||||
#include "shared/global_context.h"
|
||||
|
||||
#define USE_PIC_VIEW_APP 0
|
||||
#if USE_PIC_VIEW_APP
|
||||
#include "picview/picview_app.h"
|
||||
#endif
|
||||
|
||||
#ifdef EPSILON_BOOT_PROMPT
|
||||
#include "on_boarding/pop_up_controller.h"
|
||||
#endif
|
||||
@@ -42,7 +37,7 @@ public:
|
||||
VariableBoxController * variableBoxController();
|
||||
void suspend(bool checkIfPowerKeyReleased = false);
|
||||
virtual bool dispatchEvent(Ion::Events::Event event) override;
|
||||
void switchTo(App::Snapshot * snapshot) override;
|
||||
bool switchTo(App::Snapshot * snapshot) override;
|
||||
void run() override;
|
||||
bool updateBatteryState();
|
||||
void refreshPreferences();
|
||||
@@ -70,9 +65,6 @@ private:
|
||||
|
||||
AppsWindow m_window;
|
||||
EmptyBatteryWindow m_emptyBatteryWindow;
|
||||
#if USE_PIC_VIEW_APP
|
||||
PicViewApp m_picViewApp;
|
||||
#endif
|
||||
Shared::GlobalContext m_globalContext;
|
||||
MathToolbox m_mathToolbox;
|
||||
VariableBoxController m_variableBoxController;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
apps += Calculation::App
|
||||
app_headers += apps/calculation/app.h
|
||||
|
||||
app_objs += $(addprefix apps/calculation/,\
|
||||
app.o\
|
||||
calculation.o\
|
||||
calculation_store.o\
|
||||
edit_expression_controller.o\
|
||||
expression_field.o\
|
||||
history_view_cell.o\
|
||||
history_controller.o\
|
||||
scrollable_expression_view.o\
|
||||
selectable_table_view.o\
|
||||
app_src += $(addprefix apps/calculation/,\
|
||||
app.cpp \
|
||||
calculation.cpp \
|
||||
calculation_store.cpp \
|
||||
edit_expression_controller.cpp \
|
||||
expression_field.cpp \
|
||||
history_view_cell.cpp \
|
||||
history_controller.cpp \
|
||||
scrollable_expression_view.cpp \
|
||||
selectable_table_view.cpp \
|
||||
)
|
||||
|
||||
i18n_files += $(addprefix apps/calculation/,\
|
||||
@@ -25,4 +25,4 @@ tests += $(addprefix apps/calculation/test/,\
|
||||
calculation_store.cpp\
|
||||
)
|
||||
|
||||
app_images += apps/calculation/calculation_icon.png
|
||||
$(eval $(call depends_on_image,apps/calculation/app.cpp,apps/calculation/calculation_icon.png))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include "calculation_icon.h"
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include <poincare/symbol.h>
|
||||
|
||||
using namespace Poincare;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../shared/poincare_helpers.h"
|
||||
#include <poincare/symbol.h>
|
||||
#include <poincare/undefined.h>
|
||||
#include <poincare/unreal.h>
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
|
||||
@@ -22,7 +23,14 @@ Calculation::Calculation() :
|
||||
|
||||
bool Calculation::operator==(const Calculation& c) {
|
||||
return strcmp(m_inputText, c.m_inputText) == 0
|
||||
&& strcmp(m_approximateOutputText, c.m_approximateOutputText) == 0;
|
||||
&& strcmp(m_approximateOutputText, c.m_approximateOutputText) == 0
|
||||
/* Some calculations can make appear trigonometric functions in their
|
||||
* exact output. Their argument will be different with the angle unit
|
||||
* preferences but both input and approximate output will be the same.
|
||||
* For example, i^(sqrt(3)) = cos(sqrt(3)*pi/2)+i*sin(sqrt(3)*pi/2) if
|
||||
* angle unit is radian and i^(sqrt(3)) = cos(sqrt(3)*90+i*sin(sqrt(3)*90)
|
||||
* in degree. */
|
||||
&& strcmp(m_exactOutputText, c.m_exactOutputText) == 0;
|
||||
}
|
||||
|
||||
void Calculation::reset() {
|
||||
@@ -41,9 +49,10 @@ void Calculation::setContent(const char * c, Context * context, Expression ansEx
|
||||
* to keep Ans symbol in the calculation store. */
|
||||
PoincareHelpers::Serialize(input, m_inputText, sizeof(m_inputText));
|
||||
}
|
||||
Expression exactOutput = PoincareHelpers::ParseAndSimplify(m_inputText, *context);
|
||||
Expression exactOutput;
|
||||
Expression approximateOutput;
|
||||
PoincareHelpers::ParseAndSimplifyAndApproximate(m_inputText, &exactOutput, &approximateOutput, *context);
|
||||
PoincareHelpers::Serialize(exactOutput, m_exactOutputText, sizeof(m_exactOutputText));
|
||||
Expression approximateOutput = PoincareHelpers::Approximate<double>(exactOutput, *context);
|
||||
PoincareHelpers::Serialize(approximateOutput, m_approximateOutputText, sizeof(m_approximateOutputText));
|
||||
}
|
||||
|
||||
@@ -116,7 +125,7 @@ Expression Calculation::exactOutput() {
|
||||
* 'cos(pi/4) = 0.999906' (which is true in degree). */
|
||||
Expression exactOutput = Expression::Parse(m_exactOutputText);
|
||||
if (exactOutput.isUninitialized()) {
|
||||
return Undefined();
|
||||
return Undefined::Builder();
|
||||
}
|
||||
return exactOutput;
|
||||
}
|
||||
@@ -142,21 +151,21 @@ bool Calculation::shouldOnlyDisplayApproximateOutput(Context * context) {
|
||||
}
|
||||
if (strcmp(m_exactOutputText, m_approximateOutputText) == 0) {
|
||||
/* If the exact and approximate results' texts are equal and their layouts
|
||||
* too, do not display the exact result. If, because of the number of
|
||||
* significant digits, the two layouts are not equal, we display both. */
|
||||
* too, do not display the exact result. If the two layouts are not equal
|
||||
* because of the number of significant digits, we display both. */
|
||||
return exactAndApproximateDisplayedOutputsAreEqual(context) == Calculation::EqualSign::Equal;
|
||||
}
|
||||
if (strcmp(m_exactOutputText, Undefined::Name()) == 0) {
|
||||
if (strcmp(m_exactOutputText, Undefined::Name()) == 0 || strcmp(m_approximateOutputText, Unreal::Name()) == 0) {
|
||||
// If the approximate result is 'unreal' or the exact result is 'undef'
|
||||
return true;
|
||||
}
|
||||
return input().isApproximate(*context) || exactOutput().isApproximate(*context);
|
||||
}
|
||||
|
||||
bool Calculation::shouldOnlyDisplayExactOutput() {
|
||||
/* If the approximateOutput is undef, we not not want to display it.
|
||||
* This prevents:
|
||||
/* If the approximateOutput is undef, do not display it. This prevents:
|
||||
* x->f(x) from displaying x = undef
|
||||
* x+x form displaying 2x = undef */
|
||||
* x+x from displaying 2x = undef */
|
||||
return strcmp(m_approximateOutputText, Undefined::Name()) == 0;
|
||||
}
|
||||
|
||||
@@ -167,11 +176,12 @@ Calculation::EqualSign Calculation::exactAndApproximateDisplayedOutputsAreEqual(
|
||||
constexpr int bufferSize = Constant::MaxSerializedExpressionSize;
|
||||
char buffer[bufferSize];
|
||||
Preferences * preferences = Preferences::sharedPreferences();
|
||||
Expression exactOutputExpression = Expression::ParseAndSimplify(m_exactOutputText, *context, preferences->angleUnit());
|
||||
Expression exactOutputExpression = PoincareHelpers::ParseAndSimplify(m_exactOutputText, *context);
|
||||
if (exactOutputExpression.isUninitialized()) {
|
||||
exactOutputExpression = Undefined();
|
||||
exactOutputExpression = Undefined::Builder();
|
||||
}
|
||||
m_equalSign = exactOutputExpression.isEqualToItsApproximationLayout(approximateOutput(context), buffer, bufferSize, preferences->angleUnit(), preferences->displayMode(), preferences->numberOfSignificantDigits(), *context) ? EqualSign::Equal : EqualSign::Approximation;
|
||||
Preferences::ComplexFormat complexFormat = Expression::UpdatedComplexFormatWithTextInput(preferences->complexFormat(), m_inputText);
|
||||
m_equalSign = exactOutputExpression.isEqualToItsApproximationLayout(approximateOutput(context), buffer, bufferSize, complexFormat, preferences->angleUnit(), preferences->displayMode(), preferences->numberOfSignificantDigits(), *context) ? EqualSign::Equal : EqualSign::Approximation;
|
||||
return m_equalSign;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,14 +88,14 @@ void CalculationStore::tidy() {
|
||||
|
||||
Expression CalculationStore::ansExpression(Context * context) {
|
||||
if (numberOfCalculations() == 0) {
|
||||
return Rational(0);
|
||||
return Rational::Builder(0);
|
||||
}
|
||||
Calculation * lastCalculation = calculationAtIndex(numberOfCalculations()-1);
|
||||
/* Special case: the exact output is a Store/Equal expression.
|
||||
* Store/Equal expression must be final root of an expression.
|
||||
* To avoid turning 'ans->A' in '2->A->A' (or 2->A=A) which cannot be parsed),
|
||||
* ans is replaced by the approximation output in when any Store or Equal
|
||||
* expression appears.*/
|
||||
* Store/Equal expression can only be at the root of an expression.
|
||||
* To avoid turning 'ans->A' in '2->A->A' or '2=A->A' (which cannot be
|
||||
* parsed), ans is replaced by the approximation output when any Store or
|
||||
* Equal expression appears. */
|
||||
bool exactOuptutInvolvesStoreEqual = lastCalculation->exactOutput().recursivelyMatches([](const Expression e, Context & context, bool replaceSymbols) {
|
||||
return e.type() == ExpressionNode::Type::Store || e.type() == ExpressionNode::Type::Equal;
|
||||
}, *context, false);
|
||||
|
||||
@@ -150,7 +150,7 @@ KDCoordinate HistoryController::rowHeight(int j) {
|
||||
}
|
||||
Calculation * calculation = m_calculationStore->calculationAtIndex(j);
|
||||
App * calculationApp = (App *)app();
|
||||
return calculation->height(calculationApp->localContext()) + 3*HistoryViewCell::k_digitVerticalMargin;
|
||||
return calculation->height(calculationApp->localContext()) + 4 * Metric::CommonSmallMargin;
|
||||
}
|
||||
|
||||
int HistoryController::typeAtLocation(int i, int j) {
|
||||
|
||||
@@ -10,9 +10,9 @@ namespace Calculation {
|
||||
/* HistoryViewCellDataSource */
|
||||
|
||||
HistoryViewCellDataSource::HistoryViewCellDataSource() :
|
||||
m_selectedSubviewType(HistoryViewCellDataSource::SubviewType::Output) {}
|
||||
m_selectedSubviewType(SubviewType::Output) {}
|
||||
|
||||
void HistoryViewCellDataSource::setSelectedSubviewType(HistoryViewCellDataSource::SubviewType subviewType, HistoryViewCell * cell) {
|
||||
void HistoryViewCellDataSource::setSelectedSubviewType(SubviewType subviewType, HistoryViewCell * cell) {
|
||||
m_selectedSubviewType = subviewType;
|
||||
if (cell) {
|
||||
cell->setHighlighted(cell->isHighlighted());
|
||||
@@ -39,17 +39,18 @@ Shared::ScrollableExactApproximateExpressionsView * HistoryViewCell::outputView(
|
||||
void HistoryViewCell::setEven(bool even) {
|
||||
EvenOddCell::setEven(even);
|
||||
m_inputView.setBackgroundColor(backgroundColor());
|
||||
m_scrollableOutputView.setBackgroundColor(backgroundColor());
|
||||
m_scrollableOutputView.evenOddCell()->setEven(even);
|
||||
}
|
||||
|
||||
void HistoryViewCell::setHighlighted(bool highlight) {
|
||||
assert(m_dataSource);
|
||||
m_highlighted = highlight;
|
||||
m_inputView.setBackgroundColor(backgroundColor());
|
||||
m_inputView.setExpressionBackgroundColor(backgroundColor());
|
||||
m_scrollableOutputView.evenOddCell()->setHighlighted(false);
|
||||
if (isHighlighted()) {
|
||||
if (m_dataSource->selectedSubviewType() == HistoryViewCellDataSource::SubviewType::Input) {
|
||||
m_inputView.setBackgroundColor(Palette::Select);
|
||||
m_inputView.setExpressionBackgroundColor(Palette::Select);
|
||||
} else {
|
||||
m_scrollableOutputView.evenOddCell()->setHighlighted(true);
|
||||
}
|
||||
@@ -93,20 +94,21 @@ View * HistoryViewCell::subviewAtIndex(int index) {
|
||||
}
|
||||
|
||||
void HistoryViewCell::layoutSubviews() {
|
||||
KDCoordinate width = bounds().width();
|
||||
KDCoordinate height = bounds().height();
|
||||
KDCoordinate maxFrameWidth = bounds().width();
|
||||
KDSize inputSize = m_inputView.minimalSizeForOptimalDisplay();
|
||||
if (inputSize.width() + Metric::HistoryHorizontalMargin > width) {
|
||||
m_inputView.setFrame(KDRect(Metric::HistoryHorizontalMargin, k_digitVerticalMargin, width - Metric::HistoryHorizontalMargin, inputSize.height()));
|
||||
} else {
|
||||
m_inputView.setFrame(KDRect(Metric::HistoryHorizontalMargin, k_digitVerticalMargin, inputSize.width(), inputSize.height()));
|
||||
}
|
||||
m_inputView.setFrame(KDRect(
|
||||
0,
|
||||
0,
|
||||
min(maxFrameWidth, inputSize.width()),
|
||||
inputSize.height()
|
||||
));
|
||||
KDSize outputSize = m_scrollableOutputView.minimalSizeForOptimalDisplay();
|
||||
if (outputSize.width() + Metric::HistoryHorizontalMargin > width) {
|
||||
m_scrollableOutputView.setFrame(KDRect(Metric::HistoryHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, width - Metric::HistoryHorizontalMargin, height - inputSize.height() - 3*k_digitVerticalMargin));
|
||||
} else {
|
||||
m_scrollableOutputView.setFrame(KDRect(width - outputSize.width() - Metric::HistoryHorizontalMargin, inputSize.height() + 2*k_digitVerticalMargin, outputSize.width(), height - inputSize.height() - 3*k_digitVerticalMargin));
|
||||
}
|
||||
m_scrollableOutputView.setFrame(KDRect(
|
||||
max(0, maxFrameWidth - outputSize.width()),
|
||||
inputSize.height(),
|
||||
min(maxFrameWidth, outputSize.width()),
|
||||
bounds().height() - inputSize.height()
|
||||
));
|
||||
}
|
||||
|
||||
void HistoryViewCell::setCalculation(Calculation * calculation) {
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
Output
|
||||
};
|
||||
HistoryViewCellDataSource();
|
||||
void setSelectedSubviewType(HistoryViewCellDataSource::SubviewType subviewType, HistoryViewCell * cell = nullptr);
|
||||
void setSelectedSubviewType(SubviewType subviewType, HistoryViewCell * cell = nullptr);
|
||||
SubviewType selectedSubviewType() { return m_selectedSubviewType; }
|
||||
private:
|
||||
SubviewType m_selectedSubviewType;
|
||||
@@ -42,7 +42,6 @@ public:
|
||||
void layoutSubviews() override;
|
||||
void didBecomeFirstResponder() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
constexpr static KDCoordinate k_digitVerticalMargin = 5;
|
||||
Shared::ScrollableExactApproximateExpressionsView * outputView();
|
||||
private:
|
||||
constexpr static KDCoordinate k_resultWidth = 80;
|
||||
|
||||
@@ -8,11 +8,17 @@ ScrollableExpressionView::ScrollableExpressionView(Responder * parentResponder)
|
||||
ScrollableView(parentResponder, &m_expressionView, this),
|
||||
m_expressionView()
|
||||
{
|
||||
setDecoratorType(ScrollView::Decorator::Type::Arrows);
|
||||
setMargins(
|
||||
Metric::CommonSmallMargin,
|
||||
Metric::CommonLargeMargin,
|
||||
Metric::CommonSmallMargin,
|
||||
Metric::CommonLargeMargin
|
||||
);
|
||||
}
|
||||
|
||||
void ScrollableExpressionView::setLayout(Layout layout) {
|
||||
m_expressionView.setLayout(layout);
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void ScrollableExpressionView::setBackgroundColor(KDColor backgroundColor) {
|
||||
@@ -20,8 +26,8 @@ void ScrollableExpressionView::setBackgroundColor(KDColor backgroundColor) {
|
||||
ScrollableView::setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
KDSize ScrollableExpressionView::minimalSizeForOptimalDisplay() const {
|
||||
return m_expressionView.minimalSizeForOptimalDisplay();
|
||||
void ScrollableExpressionView::setExpressionBackgroundColor(KDColor backgroundColor) {
|
||||
m_expressionView.setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ public:
|
||||
ScrollableExpressionView(Responder * parentResponder);
|
||||
void setLayout(Poincare::Layout layout);
|
||||
void setBackgroundColor(KDColor backgroundColor) override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
void setExpressionBackgroundColor(KDColor backgroundColor);
|
||||
private:
|
||||
ExpressionView m_expressionView;
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ CalculationSelectableTableView::CalculationSelectableTableView(Responder * paren
|
||||
{
|
||||
setVerticalCellOverlap(0);
|
||||
setMargins(0);
|
||||
setShowsIndicators(false);
|
||||
setDecoratorType(ScrollView::Decorator::Type::None);
|
||||
}
|
||||
|
||||
void CalculationSelectableTableView::scrollToCell(int i, int j) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <quiz.h>
|
||||
#include <apps/shared/global_context.h>
|
||||
#include <poincare/test/helper.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "../calculation_store.h"
|
||||
@@ -13,7 +14,7 @@ void assert_store_is(CalculationStore * store, const char * result[10]) {
|
||||
}
|
||||
}
|
||||
|
||||
QUIZ_CASE(calculation_store) {
|
||||
QUIZ_CASE(calculation_store_ring_buffer) {
|
||||
Shared::GlobalContext globalContext;
|
||||
CalculationStore store;
|
||||
quiz_assert(CalculationStore::k_maxNumberOfCalculations == 10);
|
||||
@@ -50,7 +51,7 @@ QUIZ_CASE(calculation_store) {
|
||||
store.deleteAll();
|
||||
}
|
||||
|
||||
QUIZ_CASE(calculation_display_exact_approximate) {
|
||||
QUIZ_CASE(calculation_ans) {
|
||||
Shared::GlobalContext globalContext;
|
||||
CalculationStore store;
|
||||
|
||||
@@ -65,49 +66,84 @@ QUIZ_CASE(calculation_display_exact_approximate) {
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayApproximateOutput(&globalContext) == true);
|
||||
quiz_assert(strcmp(lastCalculation->approximateOutputText(),"2.6366666666667") == 0);
|
||||
|
||||
store.deleteAll();
|
||||
store.push("1/2", &globalContext);
|
||||
lastCalculation = store.calculationAtIndex(1);
|
||||
quiz_assert(lastCalculation->exactAndApproximateDisplayedOutputsAreEqual(&globalContext) == ::Calculation::Calculation::EqualSign::Equal);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayExactOutput() == false);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayApproximateOutput(&globalContext) == false);
|
||||
|
||||
store.deleteAll();
|
||||
store.push("1/3", &globalContext);
|
||||
lastCalculation = store.calculationAtIndex(1);
|
||||
quiz_assert(lastCalculation->exactAndApproximateDisplayedOutputsAreEqual(&globalContext) == ::Calculation::Calculation::EqualSign::Approximation);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayExactOutput() == false);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayApproximateOutput(&globalContext) == false);
|
||||
|
||||
store.deleteAll();
|
||||
store.push("1/0", &globalContext);
|
||||
lastCalculation = store.calculationAtIndex(1);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayExactOutput() == true);
|
||||
quiz_assert(strcmp(lastCalculation->approximateOutputText(),"undef") == 0);
|
||||
|
||||
store.deleteAll();
|
||||
store.push("2x-x", &globalContext);
|
||||
lastCalculation = store.calculationAtIndex(1);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayExactOutput() == true);
|
||||
quiz_assert(strcmp(lastCalculation->exactOutputText(),"x") == 0);
|
||||
|
||||
store.deleteAll();
|
||||
store.push("[[1,2,3]]", &globalContext);
|
||||
lastCalculation = store.calculationAtIndex(1);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayExactOutput() == false);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayApproximateOutput(&globalContext) == true);
|
||||
|
||||
store.deleteAll();
|
||||
store.push("[[1,x,3]]", &globalContext);
|
||||
lastCalculation = store.calculationAtIndex(1);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayExactOutput() == false);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayApproximateOutput(&globalContext) == true);
|
||||
|
||||
store.deleteAll();
|
||||
store.push("28^7", &globalContext);
|
||||
lastCalculation = store.calculationAtIndex(1);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayExactOutput() == false);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayApproximateOutput(&globalContext) == false);
|
||||
|
||||
store.deleteAll();
|
||||
}
|
||||
|
||||
void assertCalculationDisplay(const char * input, bool displayExactOutput, bool displayApproximateOutput, ::Calculation::Calculation::EqualSign sign, const char * exactOutput, const char * approximateOutput, Context * context, CalculationStore * store) {
|
||||
char buffer[500];
|
||||
strlcpy(buffer, input, sizeof(buffer));
|
||||
translate_in_special_chars(buffer);
|
||||
store->push(buffer, context);
|
||||
::Calculation::Calculation * lastCalculation = store->calculationAtIndex(1);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayExactOutput() == displayExactOutput);
|
||||
quiz_assert(lastCalculation->shouldOnlyDisplayApproximateOutput(context) == displayApproximateOutput);
|
||||
if (sign != ::Calculation::Calculation::EqualSign::Unknown) {
|
||||
quiz_assert(lastCalculation->exactAndApproximateDisplayedOutputsAreEqual(context) == sign);
|
||||
}
|
||||
if (exactOutput) {
|
||||
strlcpy(buffer, exactOutput, sizeof(buffer));
|
||||
translate_in_special_chars(buffer);
|
||||
quiz_assert(strcmp(lastCalculation->exactOutputText(), buffer) == 0);
|
||||
}
|
||||
if (approximateOutput) {
|
||||
strlcpy(buffer, approximateOutput, sizeof(buffer));
|
||||
translate_in_special_chars(buffer);
|
||||
quiz_assert(strcmp(lastCalculation->approximateOutputText(),buffer) == 0);
|
||||
}
|
||||
store->deleteAll();
|
||||
}
|
||||
|
||||
QUIZ_CASE(calculation_display_exact_approximate) {
|
||||
Shared::GlobalContext globalContext;
|
||||
CalculationStore store;
|
||||
|
||||
assertCalculationDisplay("1/2", false, false, ::Calculation::Calculation::EqualSign::Equal, nullptr, nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("1/3", false, false, ::Calculation::Calculation::EqualSign::Approximation, nullptr, nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("1/0", true, false, ::Calculation::Calculation::EqualSign::Unknown, "undef", "undef", &globalContext, &store);
|
||||
assertCalculationDisplay("2x-x", true, false, ::Calculation::Calculation::EqualSign::Unknown, "x", "undef", &globalContext, &store);
|
||||
assertCalculationDisplay("[[1,2,3]]", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("[[1,x,3]]", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("28^7", false, false, ::Calculation::Calculation::EqualSign::Unknown, nullptr, nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("3+R(2)>a", false, false, ::Calculation::Calculation::EqualSign::Approximation, "R(2)+3", nullptr, &globalContext, &store);
|
||||
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
|
||||
assertCalculationDisplay("3+2>a", false, true, ::Calculation::Calculation::EqualSign::Equal, "5", "5", &globalContext, &store);
|
||||
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
|
||||
assertCalculationDisplay("3>a", false, true, ::Calculation::Calculation::EqualSign::Equal, "3", "3", &globalContext, &store);
|
||||
Ion::Storage::sharedStorage()->recordNamed("a.exp").destroy();
|
||||
assertCalculationDisplay("3+x>f(x)", true, false, ::Calculation::Calculation::EqualSign::Unknown, "x+3", nullptr, &globalContext, &store);
|
||||
Ion::Storage::sharedStorage()->recordNamed("f.func").destroy();
|
||||
}
|
||||
|
||||
QUIZ_CASE(calculation_complex_format) {
|
||||
Shared::GlobalContext globalContext;
|
||||
CalculationStore store;
|
||||
|
||||
Poincare::Preferences::sharedPreferences()->setComplexFormat(Poincare::Preferences::ComplexFormat::Real);
|
||||
assertCalculationDisplay("1+I", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "1+I", &globalContext, &store);
|
||||
assertCalculationDisplay("R(-1)", false, true, ::Calculation::Calculation::EqualSign::Unknown, "unreal", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("ln(-2)", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "unreal", &globalContext, &store);
|
||||
assertCalculationDisplay("R(-1)*R(-1)", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "unreal", &globalContext, &store);
|
||||
assertCalculationDisplay("(-8)^(1/3)", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "-2", &globalContext, &store);
|
||||
assertCalculationDisplay("(-8)^(2/3)", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "4", &globalContext, &store);
|
||||
assertCalculationDisplay("(-2)^(1/4)", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "unreal", &globalContext, &store);
|
||||
|
||||
Poincare::Preferences::sharedPreferences()->setComplexFormat(Poincare::Preferences::ComplexFormat::Cartesian);
|
||||
assertCalculationDisplay("1+I", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "1+I", &globalContext, &store);
|
||||
assertCalculationDisplay("R(-1)", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "I", &globalContext, &store);
|
||||
assertCalculationDisplay("ln(-2)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "ln(-2)", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("R(-1)*R(-1)", false, true, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "-1", &globalContext, &store);
|
||||
assertCalculationDisplay("(-8)^(1/3)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "1+R(3)*I", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("(-8)^(2/3)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "-2+2*R(3)*I", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("(-2)^(1/4)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "root(8,4)/2+root(8,4)/2*I", nullptr, &globalContext, &store);
|
||||
|
||||
Poincare::Preferences::sharedPreferences()->setComplexFormat(Poincare::Preferences::ComplexFormat::Polar);
|
||||
assertCalculationDisplay("1+I", false, false, ::Calculation::Calculation::EqualSign::Approximation, "R(2)*X^(P/4*I)", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("R(-1)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "X^(P/2*I)", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("ln(-2)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "ln(-2)", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("R(-1)*R(-1)", false, false, ::Calculation::Calculation::EqualSign::Unknown, nullptr, "X^(3.1415926535898*I)", &globalContext, &store);
|
||||
assertCalculationDisplay("(-8)^(1/3)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "2*X^(P/3*I)", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("(-8)^(2/3)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "4*X^((2*P)/3*I)", nullptr, &globalContext, &store);
|
||||
assertCalculationDisplay("(-2)^(1/4)", false, false, ::Calculation::Calculation::EqualSign::Approximation, "root(2,4)*X^(P/4*I)", nullptr, &globalContext, &store);
|
||||
|
||||
Poincare::Preferences::sharedPreferences()->setComplexFormat(Poincare::Preferences::ComplexFormat::Cartesian);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
apps += Code::App
|
||||
app_headers += apps/code/app.h
|
||||
|
||||
app_objs += $(addprefix apps/code/,\
|
||||
app.o\
|
||||
console_controller.o\
|
||||
console_edit_cell.o\
|
||||
console_line_cell.o\
|
||||
console_store.o\
|
||||
editor_controller.o\
|
||||
editor_view.o\
|
||||
helpers.o\
|
||||
menu_controller.o\
|
||||
python_toolbox.o\
|
||||
python_text_area.o\
|
||||
sandbox_controller.o\
|
||||
script.o\
|
||||
script_name_cell.o\
|
||||
script_node_cell.o\
|
||||
script_parameter_controller.o\
|
||||
script_store.o\
|
||||
script_template.o\
|
||||
variable_box_controller.o\
|
||||
app_src += $(addprefix apps/code/,\
|
||||
app.cpp \
|
||||
console_controller.cpp \
|
||||
console_edit_cell.cpp \
|
||||
console_line_cell.cpp \
|
||||
console_store.cpp \
|
||||
editor_controller.cpp \
|
||||
editor_view.cpp \
|
||||
helpers.cpp \
|
||||
menu_controller.cpp \
|
||||
python_toolbox.cpp \
|
||||
python_text_area.cpp \
|
||||
sandbox_controller.cpp \
|
||||
script.cpp \
|
||||
script_name_cell.cpp \
|
||||
script_node_cell.cpp \
|
||||
script_parameter_controller.cpp \
|
||||
script_store.cpp \
|
||||
script_template.cpp \
|
||||
variable_box_controller.cpp \
|
||||
)
|
||||
|
||||
i18n_files += $(addprefix apps/code/,\
|
||||
@@ -44,4 +44,4 @@ i18n_files += $(addprefix apps/code/,\
|
||||
toolbox.universal.i18n\
|
||||
)
|
||||
|
||||
app_images += apps/code/code_icon.png
|
||||
$(eval $(call depends_on_image,apps/code/app.cpp,apps/code/code_icon.png))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include "code_icon.h"
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include "helpers.h"
|
||||
|
||||
namespace Code {
|
||||
|
||||
@@ -5,4 +5,4 @@ ExecuteScript = "Skript ausfuehren"
|
||||
AutoImportScript = "Automatischer Import in Konsole"
|
||||
DeleteScript = "Skript loeschen"
|
||||
FunctionsAndVariables = "Funktionen und Variablen"
|
||||
NonCompliantName = "Erlaubte Zeichen: a-z, 0-9, _"
|
||||
AllowedCharactersaz09 = "Erlaubte Zeichen: a-z, 0-9, _"
|
||||
|
||||
@@ -5,4 +5,4 @@ ExecuteScript = "Execute script"
|
||||
AutoImportScript = "Auto import in shell"
|
||||
DeleteScript = "Delete script"
|
||||
FunctionsAndVariables = "Functions and variables"
|
||||
NonCompliantName = "Allowed characters: a-z, 0-9, _"
|
||||
AllowedCharactersaz09 = "Allowed characters: a-z, 0-9, _"
|
||||
|
||||
@@ -5,4 +5,4 @@ ExecuteScript = "Ejecutar el archivo"
|
||||
AutoImportScript = "Importacion auto en interprete"
|
||||
DeleteScript = "Eliminar el archivo"
|
||||
FunctionsAndVariables = "Funciones y variables"
|
||||
NonCompliantName = "Caracteres permitidos : a-z, 0-9, _"
|
||||
AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _"
|
||||
|
||||
@@ -5,4 +5,4 @@ ExecuteScript = "Executer le script"
|
||||
AutoImportScript = "Importation auto dans la console"
|
||||
DeleteScript = "Supprimer le script"
|
||||
FunctionsAndVariables = "Fonctions et variables"
|
||||
NonCompliantName = "Caractères autorisés : a-z, 0-9, _"
|
||||
AllowedCharactersaz09 = "Caractères autorisés : a-z, 0-9, _"
|
||||
|
||||
@@ -5,4 +5,4 @@ ExecuteScript = "Executar o script"
|
||||
AutoImportScript = "Importacao auto no interpretador"
|
||||
DeleteScript = "Eliminar o script"
|
||||
FunctionsAndVariables = "Funções e variáveis"
|
||||
NonCompliantName = "Caracteres permitidos : a-z, 0-9, _"
|
||||
AllowedCharactersaz09 = "Caracteres permitidos : a-z, 0-9, _"
|
||||
|
||||
@@ -91,25 +91,51 @@ const char * ConsoleController::inputText(const char * prompt) {
|
||||
AppsContainer * a = (AppsContainer *)(app()->container());
|
||||
m_inputRunLoopActive = true;
|
||||
|
||||
// Set the prompt text
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
m_editCell.setPrompt(prompt);
|
||||
const char * promptText = prompt;
|
||||
char * s = const_cast<char *>(prompt);
|
||||
|
||||
if (promptText != nullptr) {
|
||||
/* Set the prompt text. If the prompt text has a '\n', put the prompt text in
|
||||
* the history until the last '\n', and put the remaining prompt text in the
|
||||
* edit cell's prompt. */
|
||||
char * lastCarriageReturn = nullptr;
|
||||
while (*s != 0) {
|
||||
if (*s == '\n') {
|
||||
lastCarriageReturn = s;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (lastCarriageReturn != nullptr) {
|
||||
printText(prompt, lastCarriageReturn-prompt+1);
|
||||
promptText = lastCarriageReturn+1;
|
||||
}
|
||||
}
|
||||
|
||||
m_editCell.setPrompt(promptText);
|
||||
m_editCell.setText("");
|
||||
|
||||
// Run new input loop
|
||||
// Reload the history
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
a->redrawWindow();
|
||||
|
||||
// Launch a new input loop
|
||||
a->runWhile([](void * a){
|
||||
ConsoleController * c = static_cast<ConsoleController *>(a);
|
||||
return c->inputRunLoopActive();
|
||||
}, this);
|
||||
|
||||
// Reset the prompt line
|
||||
// Handle the input text
|
||||
if (promptText != nullptr) {
|
||||
printText(promptText, s - promptText);
|
||||
}
|
||||
const char * text = m_editCell.text();
|
||||
printText(text, strlen(text));
|
||||
flushOutputAccumulationBufferToStore();
|
||||
m_consoleStore.deleteLastLineIfEmpty();
|
||||
|
||||
m_editCell.setPrompt(sStandardPromptText);
|
||||
|
||||
return m_editCell.text();
|
||||
return text;
|
||||
}
|
||||
|
||||
void ConsoleController::viewWillAppear() {
|
||||
@@ -242,7 +268,11 @@ bool ConsoleController::textFieldShouldFinishEditing(TextField * textField, Ion:
|
||||
}
|
||||
|
||||
bool ConsoleController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
|
||||
if (event == Ion::Events::Up && m_inputRunLoopActive) {
|
||||
if (m_inputRunLoopActive
|
||||
&& (event == Ion::Events::Up
|
||||
|| event == Ion::Events::OK
|
||||
|| event == Ion::Events::EXE))
|
||||
{
|
||||
m_inputRunLoopActive = false;
|
||||
/* We need to return true here because we want to actually exit from the
|
||||
* input run loop, which requires ending a dispatchEvent cycle. */
|
||||
@@ -302,6 +332,13 @@ void ConsoleController::displaySandbox() {
|
||||
stackViewController()->push(&m_sandboxController);
|
||||
}
|
||||
|
||||
void ConsoleController::hideSandbox() {
|
||||
if (!sandboxIsDisplayed()) {
|
||||
return;
|
||||
}
|
||||
m_sandboxController.hide();
|
||||
}
|
||||
|
||||
void ConsoleController::resetSandbox() {
|
||||
if (!sandboxIsDisplayed()) {
|
||||
return;
|
||||
@@ -313,28 +350,33 @@ void ConsoleController::resetSandbox() {
|
||||
* The text argument is not always null-terminated. */
|
||||
void ConsoleController::printText(const char * text, size_t length) {
|
||||
size_t textCutIndex = firstNewLineCharIndex(text, length);
|
||||
// If there is no new line in text, just append it to the output accumulation
|
||||
// buffer.
|
||||
if (textCutIndex >= length) {
|
||||
/* If there is no new line in text, just append it to the output
|
||||
* accumulation buffer. */
|
||||
appendTextToOutputAccumulationBuffer(text, length);
|
||||
return;
|
||||
}
|
||||
// If there is a new line in the middle of the text, we have to store at least
|
||||
// two new console lines in the console store.
|
||||
if (textCutIndex < length - 1) {
|
||||
/* If there is a new line in the middle of the text, we have to store at
|
||||
* least two new console lines in the console store. */
|
||||
printText(text, textCutIndex + 1);
|
||||
printText(&text[textCutIndex+1], length - (textCutIndex + 1));
|
||||
return;
|
||||
}
|
||||
// If there is a new line at the end of the text, we have to store the line in
|
||||
// the console store.
|
||||
if (textCutIndex == length - 1) {
|
||||
appendTextToOutputAccumulationBuffer(text, length-1);
|
||||
flushOutputAccumulationBufferToStore();
|
||||
}
|
||||
/* There is a new line at the end of the text, we have to store the line in
|
||||
* the console store. */
|
||||
assert(textCutIndex == length - 1);
|
||||
appendTextToOutputAccumulationBuffer(text, length-1);
|
||||
flushOutputAccumulationBufferToStore();
|
||||
}
|
||||
|
||||
void ConsoleController::autoImportScript(Script script, bool force) {
|
||||
if (sandboxIsDisplayed()) {
|
||||
/* The sandbox might be displayed, for instance if we are auto-importing
|
||||
* several scripts that draw at importation. In this case, we want to remove
|
||||
* the sandbox. */
|
||||
hideSandbox();
|
||||
}
|
||||
if (script.importationStatus() || force) {
|
||||
// Step 1 - Create the command "from scriptName import *".
|
||||
|
||||
@@ -357,7 +399,7 @@ void ConsoleController::autoImportScript(Script script, bool force) {
|
||||
// Step 2 - Run the command
|
||||
runAndPrintForCommand(command);
|
||||
}
|
||||
if (force) {
|
||||
if (!sandboxIsDisplayed() && force) {
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
|
||||
m_editCell.setEditing(true);
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
|
||||
// MicroPython::ExecutionEnvironment
|
||||
void displaySandbox() override;
|
||||
void hideSandbox() override;
|
||||
void resetSandbox() override;
|
||||
void printText(const char * text, size_t length) override;
|
||||
const char * inputText(const char * prompt) override;
|
||||
|
||||
@@ -31,10 +31,6 @@ ConsoleLineCell::ScrollableConsoleLineView::ScrollableConsoleLineView(Responder
|
||||
{
|
||||
}
|
||||
|
||||
KDSize ConsoleLineCell::ScrollableConsoleLineView::minimalSizeForOptimalDisplay() const {
|
||||
return m_consoleLineView.minimalSizeForOptimalDisplay();
|
||||
}
|
||||
|
||||
ConsoleLineCell::ConsoleLineCell(Responder * parentResponder) :
|
||||
HighlightCell(),
|
||||
Responder(parentResponder),
|
||||
|
||||
@@ -48,7 +48,6 @@ private:
|
||||
};
|
||||
|
||||
ScrollableConsoleLineView(Responder * parentResponder);
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
ConsoleLineView * consoleLineView() { return &m_consoleLineView; }
|
||||
private:
|
||||
ConsoleLineView m_consoleLineView;
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
#include "console_store.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace Code {
|
||||
|
||||
static inline int min(int x, int y) { return (x<y ? x : y); }
|
||||
|
||||
ConsoleStore::ConsoleStore() :
|
||||
m_history{0}
|
||||
{
|
||||
}
|
||||
|
||||
void ConsoleStore::clear() {
|
||||
assert(k_historySize > 0);
|
||||
m_history[0] = 0;
|
||||
}
|
||||
|
||||
void ConsoleStore::startNewSession() {
|
||||
if (k_historySize < 1) {
|
||||
return;
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
#define CODE_CONSOLE_STORE_H
|
||||
|
||||
#include "console_line.h"
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace Code {
|
||||
|
||||
class ConsoleStore {
|
||||
public:
|
||||
ConsoleStore();
|
||||
void clear();
|
||||
ConsoleStore() : m_history{0} {}
|
||||
void clear() { assert(k_historySize > 0); m_history[0] = 0; }
|
||||
void startNewSession();
|
||||
ConsoleLine lineAtIndex(int i) const;
|
||||
int numberOfLines() const;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "menu_controller.h"
|
||||
#include "app.h"
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include "../apps_container.h"
|
||||
#include <assert.h>
|
||||
#include <escher/metric.h>
|
||||
@@ -26,7 +26,7 @@ MenuController::MenuController(Responder * parentResponder, App * pythonDelegate
|
||||
m_shouldDisplayAddScriptRow(true)
|
||||
{
|
||||
m_selectableTableView.setMargins(0);
|
||||
m_selectableTableView.setShowsIndicators(false);
|
||||
m_selectableTableView.setDecoratorType(ScrollView::Decorator::Type::None);
|
||||
m_addNewScriptCell.setMessage(I18n::Message::AddScript);
|
||||
for (int i = 0; i < k_maxNumberOfDisplayableScriptCells; i++) {
|
||||
m_scriptCells[i].setParentResponder(&m_selectableTableView);
|
||||
@@ -49,7 +49,7 @@ void MenuController::willExitResponderChain(Responder * nextFirstResponder) {
|
||||
TextField * tf = static_cast<ScriptNameCell *>(m_selectableTableView.selectedCell())->textField();
|
||||
if (tf->isEditing()) {
|
||||
tf->setEditing(false, false);
|
||||
textFieldDidAbortEditing(tf);
|
||||
privateTextFieldDidAbortEditing(tf, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,8 @@ void MenuController::didBecomeFirstResponder() {
|
||||
assert(m_selectableTableView.selectedRow() < m_scriptStore->numberOfScripts() + 1);
|
||||
app()->setFirstResponder(&m_selectableTableView);
|
||||
#if EPSILON_GETOPT
|
||||
if (consoleController()->locked() && consoleController()->loadPythonEnvironment()) {
|
||||
if (consoleController()->locked()) {
|
||||
consoleController()->setAutoImport(true);
|
||||
stackViewController()->push(consoleController());
|
||||
return;
|
||||
}
|
||||
@@ -337,7 +338,7 @@ bool MenuController::textFieldDidFinishEditing(TextField * textField, const char
|
||||
} else if (error == Script::ErrorStatus::NameTaken) {
|
||||
app()->displayWarning(I18n::Message::NameTaken);
|
||||
} else if (error == Script::ErrorStatus::NonCompliantName) {
|
||||
app()->displayWarning(I18n::Message::NonCompliantName);
|
||||
app()->displayWarning(I18n::Message::AllowedCharactersaz09, I18n::Message::NameCannotStartWithNumber);
|
||||
} else {
|
||||
assert(error == Script::ErrorStatus::NotEnoughSpaceAvailable);
|
||||
app()->displayWarning(I18n::Message::NameTooLong);
|
||||
@@ -345,34 +346,6 @@ bool MenuController::textFieldDidFinishEditing(TextField * textField, const char
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MenuController::textFieldDidAbortEditing(TextField * textField) {
|
||||
Script script = m_scriptStore->scriptAtIndex(m_selectableTableView.selectedRow());
|
||||
const char * scriptName = script.fullName();
|
||||
if (strlen(scriptName) <= 1 + strlen(ScriptStore::k_scriptExtension)) {
|
||||
// The previous text was an empty name. Use a numbered default script name.
|
||||
char numberedDefaultName[Script::k_defaultScriptNameMaxSize];
|
||||
bool foundDefaultName = Script::DefaultName(numberedDefaultName, Script::k_defaultScriptNameMaxSize);
|
||||
if (!foundDefaultName) {
|
||||
// If we did not find a default name, delete the script
|
||||
deleteScript(script);
|
||||
return true;
|
||||
}
|
||||
Script::ErrorStatus error = script.setBaseNameWithExtension(numberedDefaultName, ScriptStore::k_scriptExtension);
|
||||
scriptName = m_scriptStore->scriptAtIndex(m_selectableTableView.selectedRow()).fullName();
|
||||
/* Because we use the numbered default name, the name should not be
|
||||
* already taken. Plus, the script could be added only if the storage has
|
||||
* enough available space to add a script named 'script99.py' */
|
||||
(void) error; // Silence the "variable unused" warning if assertions are not enabled
|
||||
assert(error == Script::ErrorStatus::None);
|
||||
updateAddScriptRowDisplay();
|
||||
}
|
||||
textField->setText(scriptName);
|
||||
m_selectableTableView.selectCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
|
||||
app()->setFirstResponder(&m_selectableTableView);
|
||||
static_cast<AppsContainer *>(const_cast<Container *>(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MenuController::textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textSizeDidChange) {
|
||||
int scriptExtensionLength = 1 + strlen(ScriptStore::k_scriptExtension);
|
||||
if (textField->isEditing() && textField->cursorLocation() > textField->draftTextLength() - scriptExtensionLength) {
|
||||
@@ -410,4 +383,39 @@ void MenuController::updateAddScriptRowDisplay() {
|
||||
m_selectableTableView.reloadData();
|
||||
}
|
||||
|
||||
bool MenuController::privateTextFieldDidAbortEditing(TextField * textField, bool menuControllerStaysInResponderChain) {
|
||||
/* If menuControllerStaysInResponderChain is false, we do not want to use
|
||||
* methods that might call setFirstResponder, because we might be in the
|
||||
* middle of another setFirstResponder call. */
|
||||
Script script = m_scriptStore->scriptAtIndex(m_selectableTableView.selectedRow());
|
||||
const char * scriptName = script.fullName();
|
||||
if (strlen(scriptName) <= 1 + strlen(ScriptStore::k_scriptExtension)) {
|
||||
// The previous text was an empty name. Use a numbered default script name.
|
||||
char numberedDefaultName[Script::k_defaultScriptNameMaxSize];
|
||||
bool foundDefaultName = Script::DefaultName(numberedDefaultName, Script::k_defaultScriptNameMaxSize);
|
||||
if (!foundDefaultName) {
|
||||
// If we did not find a default name, delete the script
|
||||
deleteScript(script);
|
||||
return true;
|
||||
}
|
||||
Script::ErrorStatus error = script.setBaseNameWithExtension(numberedDefaultName, ScriptStore::k_scriptExtension);
|
||||
scriptName = m_scriptStore->scriptAtIndex(m_selectableTableView.selectedRow()).fullName();
|
||||
/* Because we use the numbered default name, the name should not be
|
||||
* already taken. Plus, the script could be added only if the storage has
|
||||
* enough available space to add a script named 'script99.py' */
|
||||
(void) error; // Silence the "variable unused" warning if assertions are not enabled
|
||||
assert(error == Script::ErrorStatus::None);
|
||||
if (menuControllerStaysInResponderChain) {
|
||||
updateAddScriptRowDisplay();
|
||||
}
|
||||
}
|
||||
textField->setText(scriptName);
|
||||
if (menuControllerStaysInResponderChain) {
|
||||
m_selectableTableView.selectCellAtLocation(m_selectableTableView.selectedColumn(), m_selectableTableView.selectedRow());
|
||||
app()->setFirstResponder(&m_selectableTableView);
|
||||
}
|
||||
static_cast<AppsContainer *>(const_cast<Container *>(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,9 @@ public:
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidReceiveEvent(TextField * textField, 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 {
|
||||
return privateTextFieldDidAbortEditing(textField, true);
|
||||
}
|
||||
bool textFieldDidHandleEvent(TextField * textField, bool returnValue, bool textSizeDidChange) override;
|
||||
|
||||
/* ButtonRowDelegate */
|
||||
@@ -74,6 +76,7 @@ private:
|
||||
void editScriptAtIndex(int scriptIndex);
|
||||
void numberedDefaultScriptName(char * buffer);
|
||||
void updateAddScriptRowDisplay();
|
||||
bool privateTextFieldDidAbortEditing(TextField * textField, bool menuControllerStaysInResponderChain);
|
||||
ScriptStore * m_scriptStore;
|
||||
ScriptNameCell m_scriptCells[k_maxNumberOfDisplayableScriptCells];
|
||||
EvenOddCellWithEllipsis m_scriptParameterCells[k_maxNumberOfDisplayableScriptCells];
|
||||
|
||||
@@ -20,6 +20,10 @@ void SandboxController::reset() {
|
||||
redrawWindow();
|
||||
}
|
||||
|
||||
void SandboxController::hide() {
|
||||
stackViewController()->pop();
|
||||
}
|
||||
|
||||
void SandboxController::viewWillAppear() {
|
||||
assert(m_executionEnvironment != nullptr);
|
||||
m_executionEnvironment->setSandboxIsDisplayed(true);
|
||||
|
||||
@@ -14,6 +14,7 @@ public:
|
||||
SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment);
|
||||
StackViewController * stackViewController();
|
||||
void reset();
|
||||
void hide();
|
||||
|
||||
// ViewController
|
||||
View * view() override { return &m_solidColorView; }
|
||||
|
||||
@@ -37,17 +37,38 @@ bool Script::DefaultName(char buffer[], size_t bufferSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isSmallLetterOrUnderscoreChar(const char c) {
|
||||
return (c >= 'a' && c <= 'z') || c == '_';
|
||||
}
|
||||
bool isNumberChar(const char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
bool Script::nameCompliant(const char * name) {
|
||||
/* The name format is [a-z0-9_\.]+ */
|
||||
const char * currentChar = name;
|
||||
while (*currentChar != 0) {
|
||||
if ((*currentChar >= 'a' && *currentChar <= 'z') || *currentChar == '_' || (*currentChar >= '0' && *currentChar <= '9') || *currentChar == '.') {
|
||||
currentChar++;
|
||||
continue;
|
||||
}
|
||||
/* We allow here the empty script name ".py", because it is the name used to
|
||||
* create a new empty script. When naming or renaming a script, we check
|
||||
* elsewhere that the name is no longer empty.
|
||||
* The name format is ([a-z_][a-z0-9_]*)*\.py
|
||||
*
|
||||
* We do not allow upper cases in the script names because script names are
|
||||
* used in the URLs of the NumWorks workshop website and we do not want
|
||||
* problems with case sensitivity. */
|
||||
const char * c = name;
|
||||
if (*c == 0 || (!isSmallLetterOrUnderscoreChar(*c) && *c != '.')) {
|
||||
/* The name cannot be empty. Its first letter must be in [a-z_] or the
|
||||
* extension dot. */
|
||||
return false;
|
||||
}
|
||||
return name != currentChar;
|
||||
while (*c != 0) {
|
||||
if (*c == '.' && strcmp(c+1, ScriptStore::k_scriptExtension) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (!isSmallLetterOrUnderscoreChar(*c) && !isNumberChar(*c)) {
|
||||
return false;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Script::importationStatus() const {
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
private:
|
||||
constexpr static size_t k_extensionLength = 1+ScriptStore::k_scriptExtensionLength; // '.' + "py"
|
||||
constexpr static KDCoordinate k_leftMargin = Metric::HistoryHorizontalMargin;
|
||||
constexpr static KDCoordinate k_leftMargin = Metric::CommonLargeMargin;
|
||||
|
||||
// View
|
||||
int numberOfSubviews() const override { return 1; }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define CODE_SCRIPT_PARAMETER_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include "script_store.h"
|
||||
|
||||
namespace Code {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "empty_battery_window.h"
|
||||
#include "global_preferences.h"
|
||||
#include "i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
extern "C" {
|
||||
#include <assert.h>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "exam_pop_up_controller.h"
|
||||
#include "apps_container.h"
|
||||
#include "i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include "global_preferences.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef APPS_GLOBAL_PREFERENCES_H
|
||||
#define APPS_GLOBAL_PREFERENCES_H
|
||||
|
||||
#include "i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
class GlobalPreferences {
|
||||
public:
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
apps += Graph::App
|
||||
app_headers += apps/graph/app.h
|
||||
|
||||
app_objs += $(addprefix apps/graph/,\
|
||||
app.o\
|
||||
storage_cartesian_function_store.o\
|
||||
graph/banner_view.o\
|
||||
graph/calculation_graph_controller.o\
|
||||
graph/calculation_parameter_controller.o\
|
||||
graph/curve_parameter_controller.o\
|
||||
graph/extremum_graph_controller.o\
|
||||
graph/graph_controller.o\
|
||||
graph/graph_controller_helper.o\
|
||||
graph/graph_view.o\
|
||||
graph/integral_graph_controller.o\
|
||||
graph/intersection_graph_controller.o\
|
||||
graph/root_graph_controller.o\
|
||||
graph/tangent_graph_controller.o\
|
||||
list/list_parameter_controller.o\
|
||||
list/storage_list_controller.o\
|
||||
list/text_field_function_title_cell.o\
|
||||
values/storage_derivative_parameter_controller.o\
|
||||
values/storage_function_parameter_controller.o\
|
||||
values/storage_values_controller.o\
|
||||
app_src += $(addprefix apps/graph/,\
|
||||
app.cpp \
|
||||
storage_cartesian_function_store.cpp \
|
||||
graph/banner_view.cpp \
|
||||
graph/calculation_graph_controller.cpp \
|
||||
graph/calculation_parameter_controller.cpp \
|
||||
graph/curve_parameter_controller.cpp \
|
||||
graph/extremum_graph_controller.cpp \
|
||||
graph/graph_controller.cpp \
|
||||
graph/graph_controller_helper.cpp \
|
||||
graph/graph_view.cpp \
|
||||
graph/integral_graph_controller.cpp \
|
||||
graph/intersection_graph_controller.cpp \
|
||||
graph/root_graph_controller.cpp \
|
||||
graph/tangent_graph_controller.cpp \
|
||||
list/list_parameter_controller.cpp \
|
||||
list/storage_list_controller.cpp \
|
||||
list/text_field_function_title_cell.cpp \
|
||||
values/storage_derivative_parameter_controller.cpp \
|
||||
values/storage_function_parameter_controller.cpp \
|
||||
values/storage_values_controller.cpp \
|
||||
)
|
||||
|
||||
i18n_files += $(addprefix apps/graph/,\
|
||||
@@ -32,4 +32,4 @@ i18n_files += $(addprefix apps/graph/,\
|
||||
base.pt.i18n\
|
||||
)
|
||||
|
||||
app_images += apps/graph/graph_icon.png
|
||||
$(eval $(call depends_on_image,apps/graph/app.cpp,apps/graph/graph_icon.png))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include "graph_icon.h"
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
using namespace Poincare;
|
||||
using namespace Shared;
|
||||
|
||||
@@ -21,4 +21,3 @@ DerivativeFunctionColumn = "Spalte der Ableitungsfunktion"
|
||||
HideDerivativeColumn = "Ableitungsfunktion ausblenden"
|
||||
AllowedCharactersAZaz09 = "Erlaubte Zeichen: A-Z, a-z, 0-9, _"
|
||||
ReservedName = "Reserviertes Wort"
|
||||
NameCannotStartWithNumber = "Ein name darf nicht mit einer Zahl beginnen"
|
||||
|
||||
@@ -21,4 +21,3 @@ DerivativeFunctionColumn = "Derivative function column"
|
||||
HideDerivativeColumn = "Hide the derivative function"
|
||||
AllowedCharactersAZaz09 = "Allowed characters: A-Z, a-z, 0-9, _"
|
||||
ReservedName = "Reserved name"
|
||||
NameCannotStartWithNumber = "A name cannot start with a number"
|
||||
|
||||
@@ -21,4 +21,3 @@ DerivativeFunctionColumn = "Columna de la derivada"
|
||||
HideDerivativeColumn = "Ocultar la derivada"
|
||||
AllowedCharactersAZaz09 = "Caracteres permitidos : A-Z, a-z, 0-9, _"
|
||||
ReservedName = "Nombre reservado"
|
||||
NameCannotStartWithNumber = "Un nombre no puede empezar con un número"
|
||||
|
||||
@@ -21,4 +21,3 @@ DerivativeFunctionColumn = "Colonne de la fonction derivee"
|
||||
HideDerivativeColumn = "Masquer la fonction derivee"
|
||||
AllowedCharactersAZaz09 = "Caractères autorisés : A-Z, a-z, 0-9, _"
|
||||
ReservedName = "Nom réservé"
|
||||
NameCannotStartWithNumber = "Un nom ne peut pas commencer par un chiffre"
|
||||
|
||||
@@ -21,4 +21,3 @@ DerivativeFunctionColumn = "Coluna da funcao derivada"
|
||||
HideDerivativeColumn = "Esconder funcao derivada"
|
||||
AllowedCharactersAZaz09 = "Caracteres permitidos : A-Z, a-z, 0-9, _"
|
||||
ReservedName = "Nome reservado"
|
||||
NameCannotStartWithNumber = "Um nome não pode começar com um número"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "banner_view.h"
|
||||
#include "../../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Graph {
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "root_graph_controller.h"
|
||||
#include "graph_view.h"
|
||||
#include "banner_view.h"
|
||||
#include "../../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Graph {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "curve_parameter_controller.h"
|
||||
#include "graph_controller.h"
|
||||
#include "../../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Shared;
|
||||
|
||||
@@ -5,6 +5,8 @@ using namespace Shared;
|
||||
|
||||
namespace Graph {
|
||||
|
||||
static inline float max(float x, float y) { return (x>y ? x : y); }
|
||||
|
||||
GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, StorageCartesianFunctionStore * functionStore, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
|
||||
StorageFunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion),
|
||||
m_bannerView(),
|
||||
@@ -37,17 +39,17 @@ void GraphController::setDisplayDerivativeInBanner(bool displayDerivative) {
|
||||
m_displayDerivativeInBanner = displayDerivative;
|
||||
}
|
||||
|
||||
float GraphController::interestingXRange() {
|
||||
float GraphController::interestingXHalfRange() const {
|
||||
float characteristicRange = 0.0f;
|
||||
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
|
||||
for (int i = 0; i < functionStore()->numberOfActiveFunctions(); i++) {
|
||||
ExpiringPointer<StorageCartesianFunction> f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i));
|
||||
float fRange = f->expressionReduced(myApp->localContext()).characteristicXRange(*(myApp->localContext()), Poincare::Preferences::sharedPreferences()->angleUnit());
|
||||
if (!std::isnan(fRange)) {
|
||||
characteristicRange = fRange > characteristicRange ? fRange : characteristicRange;
|
||||
characteristicRange = max(fRange, characteristicRange);
|
||||
}
|
||||
}
|
||||
return (characteristicRange > 0.0f ? 1.6f*characteristicRange : 10.0f);
|
||||
return (characteristicRange > 0.0f ? 1.6f*characteristicRange : InteractiveCurveViewRangeDelegate::interestingXHalfRange());
|
||||
}
|
||||
|
||||
int GraphController::estimatedBannerNumberOfLines() const {
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
void viewWillAppear() override;
|
||||
bool displayDerivativeInBanner() const;
|
||||
void setDisplayDerivativeInBanner(bool displayDerivative);
|
||||
float interestingXRange() override;
|
||||
float interestingXHalfRange() const override;
|
||||
private:
|
||||
int estimatedBannerNumberOfLines() const override;
|
||||
void selectFunctionWithCursor(int functionIndex) override;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "storage_list_controller.h"
|
||||
#include "../app.h"
|
||||
#include "../../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include <assert.h>
|
||||
#include <escher/metric.h>
|
||||
#include <apps/apps_container.h>
|
||||
@@ -33,13 +33,20 @@ const char * StorageListController::title() {
|
||||
void StorageListController::renameSelectedFunction() {
|
||||
assert(selectedColumn() == 0);
|
||||
assert(selectedRow() >= 0 && selectedRow() < numberOfRows()-1); // TODO change if sometimes the addFunction row is not displayed
|
||||
|
||||
// Increase the size of the name column
|
||||
computeTitlesColumnWidth(true);
|
||||
selectableTableView()->reloadData();
|
||||
|
||||
static_cast<AppsContainer *>(const_cast<Container *>(app()->container()))->setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::AlphaLock);
|
||||
TextFieldFunctionTitleCell * selectedTitleCell = (TextFieldFunctionTitleCell *)(selectableTableView()->selectedCell());
|
||||
selectedTitleCell->setHorizontalAlignment(1.0f);
|
||||
app()->setFirstResponder(selectedTitleCell);
|
||||
selectedTitleCell->setEditing(true);
|
||||
}
|
||||
|
||||
bool StorageListController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
|
||||
assert(textField != nullptr);
|
||||
// Compute the new name
|
||||
size_t textLength = strlen(text);
|
||||
size_t argumentLength = StorageFunction::k_parenthesedArgumentLength;
|
||||
@@ -107,6 +114,10 @@ bool StorageListController::textFieldDidFinishEditing(TextField * textField, con
|
||||
}
|
||||
|
||||
bool StorageListController::textFieldDidAbortEditing(TextField * textField) {
|
||||
assert(textField != nullptr);
|
||||
// Put the name column back to normal size
|
||||
computeTitlesColumnWidth();
|
||||
selectableTableView()->reloadData();
|
||||
ExpiringPointer<StorageFunction> function = modelStore()->modelForRecord(modelStore()->recordAtIndex(selectedRow()));
|
||||
setFunctionNameInTextField(function, textField);
|
||||
m_selectableTableView.selectedCell()->setHighlighted(true);
|
||||
@@ -120,6 +131,7 @@ bool StorageListController::textFieldShouldFinishEditing(TextField * textField,
|
||||
}
|
||||
|
||||
bool StorageListController::textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) {
|
||||
assert(textField != nullptr);
|
||||
if (textField->isEditing() && textField->shouldFinishEditing(event)) {
|
||||
return false;
|
||||
}
|
||||
@@ -145,8 +157,14 @@ HighlightCell * StorageListController::expressionCells(int index) {
|
||||
}
|
||||
|
||||
void StorageListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) {
|
||||
assert(cell != nullptr);
|
||||
assert(j >= 0 && j < modelStore()->numberOfModels());
|
||||
TextFieldFunctionTitleCell * titleCell = static_cast<TextFieldFunctionTitleCell *>(cell);
|
||||
// Update the corresponding expression cell in order to get the baseline
|
||||
StorageExpressionModelListController::willDisplayExpressionCellAtIndex(m_selectableTableView.cellAtLocation(1, j), j);
|
||||
titleCell->setBaseline(baseline(j));
|
||||
if (!titleCell->isEditing()) {
|
||||
// Set name and color if the name is not being edited
|
||||
ExpiringPointer<StorageFunction> function = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
|
||||
setFunctionNameInTextField(function, titleCell->textField());
|
||||
KDColor functionNameColor = function->isActive() ? function->color() : Palette::GreyDark;
|
||||
@@ -155,6 +173,8 @@ void StorageListController::willDisplayTitleCellAtIndex(HighlightCell * cell, in
|
||||
}
|
||||
|
||||
void StorageListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) {
|
||||
assert(cell != nullptr);
|
||||
assert(j >= 0 && j < modelStore()->numberOfModels());
|
||||
Shared::StorageFunctionListController::willDisplayExpressionCellAtIndex(cell, j);
|
||||
FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell;
|
||||
ExpiringPointer<StorageFunction> f = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
|
||||
@@ -163,9 +183,20 @@ void StorageListController::willDisplayExpressionCellAtIndex(HighlightCell * cel
|
||||
}
|
||||
|
||||
void StorageListController::setFunctionNameInTextField(ExpiringPointer<StorageFunction> function, TextField * textField) {
|
||||
assert(textField != nullptr);
|
||||
char bufferName[BufferTextView::k_maxNumberOfChar];
|
||||
function->nameWithArgument(bufferName, BufferTextView::k_maxNumberOfChar, modelStore()->symbol());
|
||||
textField->setText(bufferName);
|
||||
}
|
||||
|
||||
KDCoordinate StorageListController::privateBaseline(int j) const {
|
||||
assert(j >= 0 && j < const_cast<StorageListController *>(this)->modelStore()->numberOfModels());
|
||||
Shared::FunctionExpressionCell * cell = static_cast<Shared::FunctionExpressionCell *>((const_cast<SelectableTableView *>(&m_selectableTableView))->cellAtLocation(1, j));
|
||||
Poincare::Layout layout = cell->layout();
|
||||
if (layout.isUninitialized()) {
|
||||
return -1;
|
||||
}
|
||||
return 0.5*(const_cast<StorageListController *>(this)->rowHeight(j)-layout.layoutSize().height())+layout.baseline();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ private:
|
||||
return static_cast<Shared::TextFieldDelegateApp *>(app());
|
||||
}
|
||||
void setFunctionNameInTextField(Shared::ExpiringPointer<Shared::StorageFunction> function, TextField * textField);
|
||||
KDCoordinate privateBaseline(int j) const override;
|
||||
TextFieldFunctionTitleCell m_functionTitleCells[k_maxNumberOfDisplayableRows];
|
||||
Shared::FunctionExpressionCell m_expressionCells[k_maxNumberOfDisplayableRows];
|
||||
ListParameterController m_parameterController;
|
||||
|
||||
@@ -4,11 +4,15 @@
|
||||
|
||||
namespace Graph {
|
||||
|
||||
static inline float min(float x, float y) { return (x<y ? x : y); }
|
||||
static inline float max(float x, float y) { return (x>y ? x : y); }
|
||||
|
||||
TextFieldFunctionTitleCell::TextFieldFunctionTitleCell(StorageListController * listController, Orientation orientation, const KDFont * font) :
|
||||
Shared::FunctionTitleCell(orientation),
|
||||
Responder(listController),
|
||||
m_textField(Shared::StorageFunction::k_parenthesedArgumentLength, this, m_textFieldBuffer, m_textFieldBuffer, k_textFieldBufferSize, nullptr, listController, false, font, 0.5f, 0.5f)
|
||||
{}
|
||||
m_textField(Shared::StorageFunction::k_parenthesedArgumentLength, this, m_textFieldBuffer, m_textFieldBuffer, k_textFieldBufferSize, nullptr, listController, false, font, 1.0f, 0.5f)
|
||||
{
|
||||
}
|
||||
|
||||
void TextFieldFunctionTitleCell::setHighlighted(bool highlight) {
|
||||
EvenOddCell::setHighlighted(highlight);
|
||||
@@ -44,8 +48,21 @@ void TextFieldFunctionTitleCell::setText(const char * title) {
|
||||
m_textField.setText(title);
|
||||
}
|
||||
|
||||
void TextFieldFunctionTitleCell::setHorizontalAlignment(float alignment) {
|
||||
assert(alignment >= 0.0f && alignment <= 1.0f);
|
||||
m_textField.setAlignment(alignment, verticalAlignment());
|
||||
}
|
||||
|
||||
void TextFieldFunctionTitleCell::layoutSubviews() {
|
||||
m_textField.setFrame(textFieldFrame());
|
||||
KDRect frame = subviewFrame();
|
||||
m_textField.setFrame(frame);
|
||||
KDCoordinate maxTextFieldX = frame.width() - m_textField.minimalSizeForOptimalDisplay().width();
|
||||
float horizontalAlignment = max(
|
||||
0.0f,
|
||||
min(
|
||||
1.0f,
|
||||
((float)(maxTextFieldX - k_textFieldRightMargin))/((float)maxTextFieldX)));
|
||||
m_textField.setAlignment(horizontalAlignment, verticalAlignment());
|
||||
}
|
||||
|
||||
void TextFieldFunctionTitleCell::didBecomeFirstResponder() {
|
||||
@@ -54,12 +71,10 @@ void TextFieldFunctionTitleCell::didBecomeFirstResponder() {
|
||||
}
|
||||
}
|
||||
|
||||
KDRect TextFieldFunctionTitleCell::textFieldFrame() const {
|
||||
KDRect textFrame(0, k_colorIndicatorThickness, bounds().width(), bounds().height() - k_colorIndicatorThickness);
|
||||
if (m_orientation == Orientation::VerticalIndicator){
|
||||
textFrame = KDRect(k_colorIndicatorThickness, 0, bounds().width() - k_colorIndicatorThickness-k_separatorThickness, bounds().height()-k_separatorThickness);
|
||||
}
|
||||
return textFrame;
|
||||
float TextFieldFunctionTitleCell::verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const {
|
||||
assert(m_orientation == Orientation::VerticalIndicator);
|
||||
KDCoordinate glyphHeight = font()->glyphSize().height();
|
||||
return ((float)(expressionBaseline - glyphHeight/2))/((float)rowHeight+1-glyphHeight);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public:
|
||||
void setEditing(bool editing);
|
||||
bool isEditing() const;
|
||||
void setText(const char * textContent);
|
||||
void setHorizontalAlignment(float alignment);
|
||||
|
||||
// FunctionTitleCell
|
||||
void setColor(KDColor color) override;
|
||||
@@ -38,10 +39,10 @@ public:
|
||||
|
||||
// Responder
|
||||
void didBecomeFirstResponder() override;
|
||||
protected:
|
||||
KDRect textFieldFrame() const;
|
||||
private:
|
||||
constexpr static KDCoordinate k_textFieldRightMargin = 4;
|
||||
constexpr static int k_textFieldBufferSize = Shared::StorageFunction::k_maxNameWithArgumentSize;
|
||||
float verticalAlignmentGivenExpressionBaselineAndRowHeight(KDCoordinate expressionBaseline, KDCoordinate rowHeight) const override;
|
||||
Shared::TextFieldWithExtension m_textField;
|
||||
char m_textFieldBuffer[k_textFieldBufferSize];
|
||||
};
|
||||
|
||||
@@ -19,7 +19,9 @@ bool StorageFunctionParameterController::handleEvent(Ion::Events::Event event) {
|
||||
switch (selectedRow()) {
|
||||
case 0:
|
||||
{
|
||||
function()->setDisplayDerivative(!function()->displayDerivative());
|
||||
bool isDisplayingDerivative = function()->displayDerivative();
|
||||
function()->setDisplayDerivative(!isDisplayingDerivative);
|
||||
m_valuesController->selectCellAtLocation(isDisplayingDerivative ? m_selectedFunctionColumn : m_selectedFunctionColumn + 1, m_valuesController->selectedRow());
|
||||
m_selectableTableView.reloadData();
|
||||
return true;
|
||||
}
|
||||
@@ -57,9 +59,7 @@ int StorageFunctionParameterController::reusableCellCount() {
|
||||
|
||||
void StorageFunctionParameterController::viewWillAppear() {
|
||||
StorageValuesFunctionParameterController::viewWillAppear();
|
||||
if (function()->displayDerivative()) {
|
||||
m_valuesController->selectCellAtLocation(m_valuesController->selectedColumn()+1, m_valuesController->selectedRow());
|
||||
}
|
||||
m_selectedFunctionColumn = m_valuesController->selectedColumn();
|
||||
}
|
||||
|
||||
void StorageFunctionParameterController::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
|
||||
@@ -27,6 +27,8 @@ private:
|
||||
#endif
|
||||
MessageTableCellWithSwitch m_displayDerivativeColumn;
|
||||
StorageValuesController * m_valuesController;
|
||||
// Index of the column corresponding to the function in the values controller
|
||||
int m_selectedFunctionColumn;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
app_objs += $(addprefix apps/hardware_test/,\
|
||||
app.o\
|
||||
arrow_view.o\
|
||||
battery_test_controller.o\
|
||||
code_128b_view.o\
|
||||
keyboard_test_controller.o\
|
||||
keyboard_view.o\
|
||||
led_test_controller.o\
|
||||
pattern.o\
|
||||
pattern_view.o\
|
||||
pop_up_controller.o\
|
||||
screen_test_controller.o\
|
||||
screen_test_controller.o\
|
||||
serial_number_controller.o\
|
||||
app_src += $(addprefix apps/hardware_test/,\
|
||||
app.cpp \
|
||||
arrow_view.cpp \
|
||||
battery_test_controller.cpp \
|
||||
code_128b_view.cpp \
|
||||
keyboard_test_controller.cpp \
|
||||
keyboard_view.cpp \
|
||||
led_test_controller.cpp \
|
||||
pattern.cpp \
|
||||
pattern_view.cpp \
|
||||
pop_up_controller.cpp \
|
||||
screen_test_controller.cpp \
|
||||
screen_test_controller.cpp \
|
||||
serial_number_controller.cpp \
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "pop_up_controller.h"
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include "../apps_container.h"
|
||||
#include <assert.h>
|
||||
|
||||
@@ -41,7 +41,9 @@ PopUpController::ContentView::ContentView(Responder * parentResponder) :
|
||||
m_okButton(this, I18n::Message::Ok, Invocation([](void * context, void * sender) {
|
||||
PopUpController::ContentView * view = (PopUpController::ContentView *)context;
|
||||
AppsContainer * appsContainer = (AppsContainer *)view->app()->container();
|
||||
appsContainer->switchTo(appsContainer->hardwareTestAppSnapshot());
|
||||
bool switched = appsContainer->switchTo(appsContainer->hardwareTestAppSnapshot());
|
||||
assert(switched);
|
||||
(void) switched; // Silence compilation warning about unused variable.
|
||||
return true;
|
||||
}, this), KDFont::SmallFont),
|
||||
m_warningTextView(KDFont::SmallFont, I18n::Message::Warning, 0.5, 0.5, KDColorWhite, KDColorBlack),
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
app_objs += $(addprefix apps/home/,\
|
||||
app.o\
|
||||
app_cell.o\
|
||||
controller.o\
|
||||
app_src += $(addprefix apps/home/,\
|
||||
app.cpp \
|
||||
app_cell.cpp \
|
||||
controller.cpp \
|
||||
)
|
||||
|
||||
i18n_files += $(addprefix apps/home/,\
|
||||
base.de.i18n\
|
||||
base.en.i18n\
|
||||
base.es.i18n\
|
||||
base.fr.i18n\
|
||||
base.pt.i18n\
|
||||
base.de.i18n \
|
||||
base.en.i18n \
|
||||
base.es.i18n \
|
||||
base.fr.i18n \
|
||||
base.pt.i18n \
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "app.h"
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include "../apps_container.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -11,9 +11,8 @@ Controller::ContentView::ContentView(Controller * controller, SelectableTableVie
|
||||
{
|
||||
m_selectableTableView.setVerticalCellOverlap(0);
|
||||
m_selectableTableView.setMargins(0, k_sideMargin, k_bottomMargin, k_sideMargin);
|
||||
m_selectableTableView.setColorsBackground(false);
|
||||
m_selectableTableView.setIndicatorThickness(k_indicatorThickness);
|
||||
m_selectableTableView.verticalScrollIndicator()->setMargin(k_indicatorMargin);
|
||||
m_selectableTableView.setBackgroundColor(KDColorWhite);
|
||||
static_cast<ScrollView::BarDecorator *>(m_selectableTableView.decorator())->verticalBar()->setMargin(k_indicatorMargin);
|
||||
}
|
||||
|
||||
SelectableTableView * Controller::ContentView::selectableTableView() {
|
||||
@@ -58,7 +57,9 @@ Controller::Controller(Responder * parentResponder, ::AppsContainer * container,
|
||||
|
||||
bool Controller::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
m_container->switchTo(m_container->appSnapshotAtIndex(m_selectionDataSource->selectedRow()*k_numberOfColumns+m_selectionDataSource->selectedColumn()+1));
|
||||
bool switched = m_container->switchTo(m_container->appSnapshotAtIndex(m_selectionDataSource->selectedRow()*k_numberOfColumns+m_selectionDataSource->selectedColumn()+1));
|
||||
assert(switched);
|
||||
(void) switched; // Silence compilation warning about unused variable.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ private:
|
||||
AppsContainer * m_container;
|
||||
static constexpr KDCoordinate k_sideMargin = 4;
|
||||
static constexpr KDCoordinate k_bottomMargin = 14;
|
||||
static constexpr KDCoordinate k_indicatorThickness = 15;
|
||||
static constexpr KDCoordinate k_indicatorMargin = 61;
|
||||
static constexpr int k_numberOfColumns = 3;
|
||||
static constexpr int k_maxNumberOfCells = 16;
|
||||
|
||||
@@ -116,7 +116,7 @@ def print_header(data, path, locales):
|
||||
def print_implementation(data, path, locales):
|
||||
f = open(path, 'w')
|
||||
f.write("#include \"i18n.h\"\n")
|
||||
f.write("#include \"global_preferences.h\"\n")
|
||||
f.write("#include <apps/global_preferences.h>\n")
|
||||
f.write("#include <assert.h>\n\n");
|
||||
f.write("namespace I18n {\n\n")
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
app_objs += $(addprefix apps/on_boarding/,\
|
||||
app.o\
|
||||
language_controller.o\
|
||||
logo_controller.o\
|
||||
logo_view.o\
|
||||
pop_up_controller.o\
|
||||
app_src += $(addprefix apps/on_boarding/,\
|
||||
app.cpp \
|
||||
language_controller.cpp \
|
||||
logo_controller.cpp \
|
||||
logo_view.cpp \
|
||||
pop_up_controller.cpp \
|
||||
)
|
||||
|
||||
i18n_files += $(addprefix apps/on_boarding/,\
|
||||
@@ -14,5 +14,4 @@ i18n_files += $(addprefix apps/on_boarding/,\
|
||||
base.pt.i18n\
|
||||
)
|
||||
|
||||
app_images += apps/on_boarding/logo_icon.png
|
||||
|
||||
$(eval $(call depends_on_image,apps/on_boarding/logo_view.cpp,apps/on_boarding/logo_icon.png))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "logo_controller.h"
|
||||
#include "logo_icon.h"
|
||||
|
||||
namespace OnBoarding {
|
||||
|
||||
|
||||
@@ -55,7 +55,9 @@ bool PopUpController::handleEvent(Ion::Events::Event event) {
|
||||
app()->dismissModalViewController();
|
||||
AppsContainer * appsContainer = (AppsContainer *)app()->container();
|
||||
if (appsContainer->activeApp()->snapshot() == appsContainer->onBoardingAppSnapshot()) {
|
||||
appsContainer->switchTo(appsContainer->appSnapshotAtIndex(0));
|
||||
bool switched = appsContainer->switchTo(appsContainer->appSnapshotAtIndex(0));
|
||||
assert(switched);
|
||||
(void) switched; // Silence compilation warning about unused variable.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define ON_BOARDING_POP_UP_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include "../shared/message_view.h"
|
||||
#include "../shared/ok_view.h"
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
app_objs += $(addprefix apps/picview/,\
|
||||
pic_view.o\
|
||||
picview_app.o\
|
||||
picview_controller.o\
|
||||
)
|
||||
|
||||
apps/picview/pic_view.cpp: apps/picview/image.c
|
||||
|
||||
apps/picview/image.c: apps/picview/image.raw
|
||||
@echo "RAW2C $@"
|
||||
@echo "const /* Needed otherwise the image will eat up all RAM */" > $@
|
||||
@xxd -i $^ >> $@
|
||||
|
||||
apps/picview/image.raw: apps/picview/image.png
|
||||
@echo "PNG2RAW $@"
|
||||
@ffmpeg -loglevel panic -vcodec png -i $^ -vcodec rawvideo -f rawvideo -pix_fmt rgb565 $@
|
||||
|
||||
products += $(addprefix apps/picview/, image.raw image.c)
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "pic_view.h"
|
||||
#include <assert.h>
|
||||
|
||||
PicView::PicView() :
|
||||
View() {
|
||||
}
|
||||
|
||||
#include "image.c"
|
||||
|
||||
void PicView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
KDColor * pixels = (KDColor *)apps_picview_image_raw;
|
||||
assert(apps_picview_image_raw_len == bounds().width() * bounds().height() * sizeof(KDColor));
|
||||
ctx->fillRectWithPixels(bounds(), pixels, nullptr);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef PICVIEW_PIC_VIEW_H
|
||||
#define PICVIEW_PIC_VIEW_H
|
||||
|
||||
#include <escher.h>
|
||||
|
||||
class PicView : public View {
|
||||
public:
|
||||
PicView();
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
#include "picview_app.h"
|
||||
|
||||
PicViewApp::PicViewApp(Container * container) :
|
||||
::App(container, &m_picViewController),
|
||||
m_picViewController(PicViewController(&m_modalViewController))
|
||||
{
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef PICVIEW_PICVIEW_APP_H
|
||||
#define PICVIEW_PICVIEW_APP_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "picview_controller.h"
|
||||
|
||||
class PicViewApp : public App {
|
||||
public:
|
||||
PicViewApp(Container * container);
|
||||
private:
|
||||
PicViewController m_picViewController;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,18 +0,0 @@
|
||||
#include "picview_controller.h"
|
||||
|
||||
PicViewController::PicViewController(Responder * parentResponder) :
|
||||
ViewController(parentResponder),
|
||||
m_view(PicView())
|
||||
{
|
||||
}
|
||||
|
||||
View * PicViewController::view() {
|
||||
return &m_view;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
const char * PicViewController::title() {
|
||||
return "PicView";
|
||||
}
|
||||
*/
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef PICVIEW_PICVIEW_CONTROLLER_H
|
||||
#define PICVIEW_PICVIEW_CONTROLLER_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "pic_view.h"
|
||||
|
||||
class PicViewController : public ViewController {
|
||||
public:
|
||||
PicViewController(Responder * parentResponder);
|
||||
View * view() override;
|
||||
private:
|
||||
PicView m_view;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,31 +1,30 @@
|
||||
apps += Probability::App
|
||||
app_headers += apps/probability/app.h
|
||||
|
||||
app_objs += $(addprefix apps/probability/,\
|
||||
app.o\
|
||||
calculation/calculation.o\
|
||||
calculation/discrete_calculation.o\
|
||||
calculation/left_integral_calculation.o\
|
||||
calculation/right_integral_calculation.o\
|
||||
calculation/finite_integral_calculation.o\
|
||||
calculation_controller.o\
|
||||
calculation_cell.o\
|
||||
calculation_type_controller.o\
|
||||
cell.o\
|
||||
image_cell.o\
|
||||
law/binomial_law.o\
|
||||
law/erf_inv.o\
|
||||
law/exponential_law.o\
|
||||
law/law.o\
|
||||
law/normal_law.o\
|
||||
law/one_parameter_law.o\
|
||||
law/poisson_law.o\
|
||||
law/two_parameter_law.o\
|
||||
law/uniform_law.o\
|
||||
law_controller.o\
|
||||
law_curve_view.o\
|
||||
parameters_controller.o\
|
||||
responder_image_cell.o\
|
||||
app_src += $(addprefix apps/probability/,\
|
||||
app.cpp \
|
||||
calculation/calculation.cpp \
|
||||
calculation/discrete_calculation.cpp \
|
||||
calculation/left_integral_calculation.cpp \
|
||||
calculation/right_integral_calculation.cpp \
|
||||
calculation/finite_integral_calculation.cpp \
|
||||
calculation_controller.cpp \
|
||||
calculation_cell.cpp \
|
||||
calculation_type_controller.cpp \
|
||||
cell.cpp \
|
||||
image_cell.cpp \
|
||||
law/binomial_law.cpp \
|
||||
law/erf_inv.cpp \
|
||||
law/exponential_law.cpp \
|
||||
law/law.cpp \
|
||||
law/normal_law.cpp \
|
||||
law/poisson_law.cpp \
|
||||
law/two_parameter_law.cpp \
|
||||
law/uniform_law.cpp \
|
||||
law_controller.cpp \
|
||||
law_curve_view.cpp \
|
||||
parameters_controller.cpp \
|
||||
responder_image_cell.cpp \
|
||||
)
|
||||
|
||||
i18n_files += $(addprefix apps/probability/,\
|
||||
@@ -40,25 +39,30 @@ tests += $(addprefix apps/probability/test/,\
|
||||
erf_inv.cpp\
|
||||
)
|
||||
|
||||
app_images += apps/probability/probability_icon.png
|
||||
# Image dependencies
|
||||
|
||||
app_images += $(addprefix apps/probability/images/,\
|
||||
binomial_icon.png\
|
||||
calcul1_icon.png\
|
||||
calcul2_icon.png\
|
||||
calcul3_icon.png\
|
||||
calcul4_icon.png\
|
||||
exponential_icon.png\
|
||||
focused_binomial_icon.png\
|
||||
focused_calcul1_icon.png\
|
||||
focused_calcul2_icon.png\
|
||||
focused_calcul3_icon.png\
|
||||
focused_calcul4_icon.png\
|
||||
focused_exponential_icon.png\
|
||||
focused_normal_icon.png\
|
||||
focused_poisson_icon.png\
|
||||
focused_uniform_icon.png\
|
||||
normal_icon.png\
|
||||
poisson_icon.png\
|
||||
uniform_icon.png\
|
||||
)
|
||||
$(eval $(call depends_on_image,apps/probability/app.cpp,apps/probability/probability_icon.png))
|
||||
|
||||
$(eval $(call depends_on_image,apps/probability/law_controller.cpp,$(addprefix apps/probability/images/, \
|
||||
binomial_icon.png \
|
||||
exponential_icon.png \
|
||||
focused_binomial_icon.png \
|
||||
focused_exponential_icon.png \
|
||||
focused_normal_icon.png \
|
||||
focused_poisson_icon.png \
|
||||
focused_uniform_icon.png \
|
||||
normal_icon.png \
|
||||
poisson_icon.png \
|
||||
uniform_icon.png \
|
||||
)))
|
||||
|
||||
$(eval $(call depends_on_image,$(addprefix apps/probability/,calculation_type_controller.cpp calculation_controller.cpp),$(addprefix apps/probability/images/, \
|
||||
calcul1_icon.png \
|
||||
calcul2_icon.png \
|
||||
calcul3_icon.png \
|
||||
calcul4_icon.png \
|
||||
focused_calcul1_icon.png \
|
||||
focused_calcul2_icon.png \
|
||||
focused_calcul3_icon.png \
|
||||
focused_calcul4_icon.png \
|
||||
)))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "app.h"
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include "probability_icon.h"
|
||||
#include <new>
|
||||
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
|
||||
namespace Probability {
|
||||
|
||||
Calculation::Calculation():
|
||||
m_law(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void Calculation::setLaw(Law * law) {
|
||||
m_law = law;
|
||||
compute(0);
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
RightIntegral,
|
||||
Discrete,
|
||||
};
|
||||
Calculation();
|
||||
Calculation() : m_law(nullptr) {}
|
||||
virtual ~Calculation() = default;
|
||||
virtual Type type() = 0;
|
||||
void setLaw(Law * law);
|
||||
|
||||
@@ -13,18 +13,6 @@ DiscreteCalculation::DiscreteCalculation() :
|
||||
compute(0);
|
||||
}
|
||||
|
||||
Calculation::Type DiscreteCalculation::type() {
|
||||
return Type::Discrete;
|
||||
}
|
||||
|
||||
int DiscreteCalculation::numberOfParameters() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
int DiscreteCalculation::numberOfEditableParameters() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
I18n::Message DiscreteCalculation::legendForParameterAtIndex(int index) {
|
||||
assert(index >= 0 && index < 2);
|
||||
if (index == 0) {
|
||||
@@ -49,14 +37,6 @@ double DiscreteCalculation::parameterAtIndex(int index) {
|
||||
return m_result;
|
||||
}
|
||||
|
||||
double DiscreteCalculation::lowerBound() {
|
||||
return m_abscissa;
|
||||
}
|
||||
|
||||
double DiscreteCalculation::upperBound() {
|
||||
return m_abscissa;
|
||||
}
|
||||
|
||||
void DiscreteCalculation::compute(int indexKnownElement) {
|
||||
if (m_law == nullptr) {
|
||||
return;
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
|
||||
namespace Probability {
|
||||
|
||||
class DiscreteCalculation : public Calculation {
|
||||
class DiscreteCalculation final : public Calculation {
|
||||
public:
|
||||
DiscreteCalculation();
|
||||
Type type() override;
|
||||
int numberOfParameters() override;
|
||||
int numberOfEditableParameters() override;
|
||||
Type type() override { return Type::Discrete; }
|
||||
int numberOfParameters() override { return 2; }
|
||||
int numberOfEditableParameters() override { return 1; }
|
||||
I18n::Message legendForParameterAtIndex(int index) override;
|
||||
void setParameterAtIndex(double f, int index) override;
|
||||
double parameterAtIndex(int index) override;
|
||||
double lowerBound() override;
|
||||
double upperBound() override;
|
||||
double lowerBound() override { return m_abscissa; }
|
||||
double upperBound() override { return m_abscissa; }
|
||||
private:
|
||||
void compute(int indexKnownElement) override;
|
||||
double m_abscissa;
|
||||
|
||||
@@ -15,14 +15,6 @@ FiniteIntegralCalculation::FiniteIntegralCalculation() :
|
||||
compute(0);
|
||||
}
|
||||
|
||||
Calculation::Type FiniteIntegralCalculation::type() {
|
||||
return Type::FiniteIntegral;
|
||||
}
|
||||
|
||||
int FiniteIntegralCalculation::numberOfParameters() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
int FiniteIntegralCalculation::numberOfEditableParameters() {
|
||||
if (m_law->type() == Law::Type::Normal) {
|
||||
return 3;
|
||||
@@ -67,14 +59,6 @@ double FiniteIntegralCalculation::parameterAtIndex(int index) {
|
||||
return m_result;
|
||||
}
|
||||
|
||||
double FiniteIntegralCalculation::lowerBound() {
|
||||
return m_lowerBound;
|
||||
}
|
||||
|
||||
double FiniteIntegralCalculation::upperBound() {
|
||||
return m_upperBound;
|
||||
}
|
||||
|
||||
void FiniteIntegralCalculation::compute(int indexKnownElement) {
|
||||
if (m_law == nullptr) {
|
||||
return;
|
||||
|
||||
@@ -8,14 +8,14 @@ namespace Probability {
|
||||
class FiniteIntegralCalculation : public Calculation {
|
||||
public:
|
||||
FiniteIntegralCalculation();
|
||||
Type type() override;
|
||||
int numberOfParameters() override;
|
||||
Type type() override { return Type::FiniteIntegral; }
|
||||
int numberOfParameters() override { return 3; }
|
||||
int numberOfEditableParameters() override;
|
||||
I18n::Message legendForParameterAtIndex(int index) override;
|
||||
void setParameterAtIndex(double f, int index) override;
|
||||
double parameterAtIndex(int index) override;
|
||||
double lowerBound() override;
|
||||
double upperBound() override;
|
||||
double lowerBound() override { return m_lowerBound; }
|
||||
double upperBound() override { return m_upperBound; }
|
||||
private:
|
||||
void compute(int indexKnownElement) override;
|
||||
double m_lowerBound;
|
||||
|
||||
@@ -13,14 +13,6 @@ LeftIntegralCalculation::LeftIntegralCalculation() :
|
||||
compute(0);
|
||||
}
|
||||
|
||||
Calculation::Type LeftIntegralCalculation::type() {
|
||||
return Type::LeftIntegral;
|
||||
}
|
||||
|
||||
int LeftIntegralCalculation::numberOfParameters() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
I18n::Message LeftIntegralCalculation::legendForParameterAtIndex(int index) {
|
||||
assert(index >= 0 && index < 2);
|
||||
if (index == 0) {
|
||||
@@ -48,10 +40,6 @@ double LeftIntegralCalculation::parameterAtIndex(int index) {
|
||||
return m_result;
|
||||
}
|
||||
|
||||
double LeftIntegralCalculation::upperBound() {
|
||||
return m_upperBound;
|
||||
}
|
||||
|
||||
void LeftIntegralCalculation::compute(int indexKnownElement) {
|
||||
if (m_law == nullptr) {
|
||||
return;
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
|
||||
namespace Probability {
|
||||
|
||||
class LeftIntegralCalculation : public Calculation {
|
||||
class LeftIntegralCalculation final : public Calculation {
|
||||
public:
|
||||
LeftIntegralCalculation();
|
||||
Type type() override;
|
||||
int numberOfParameters() override;
|
||||
Type type() override { return Type::LeftIntegral; }
|
||||
int numberOfParameters() override { return 2; }
|
||||
I18n::Message legendForParameterAtIndex(int index) override;
|
||||
void setParameterAtIndex(double f, int index) override;
|
||||
double parameterAtIndex(int index) override;
|
||||
double upperBound() override;
|
||||
double upperBound() override { return m_upperBound; }
|
||||
private:
|
||||
void compute(int indexKnownElement) override;
|
||||
double m_upperBound;
|
||||
|
||||
@@ -13,14 +13,6 @@ RightIntegralCalculation::RightIntegralCalculation() :
|
||||
compute(0);
|
||||
}
|
||||
|
||||
Calculation::Type RightIntegralCalculation::type() {
|
||||
return Type::RightIntegral;
|
||||
}
|
||||
|
||||
int RightIntegralCalculation::numberOfParameters() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
I18n::Message RightIntegralCalculation::legendForParameterAtIndex(int index) {
|
||||
assert(index >= 0 && index < 2);
|
||||
if (index == 0) {
|
||||
@@ -48,10 +40,6 @@ double RightIntegralCalculation::parameterAtIndex(int index) {
|
||||
return m_result;
|
||||
}
|
||||
|
||||
double RightIntegralCalculation::lowerBound() {
|
||||
return m_lowerBound;
|
||||
}
|
||||
|
||||
void RightIntegralCalculation::compute(int indexKnownElement) {
|
||||
if (m_law == nullptr) {
|
||||
return;
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
|
||||
namespace Probability {
|
||||
|
||||
class RightIntegralCalculation : public Calculation {
|
||||
class RightIntegralCalculation final : public Calculation {
|
||||
public:
|
||||
RightIntegralCalculation();
|
||||
Type type() override;
|
||||
int numberOfParameters() override;
|
||||
Type type() override { return Type::RightIntegral; }
|
||||
int numberOfParameters() override { return 2; }
|
||||
I18n::Message legendForParameterAtIndex(int index) override;
|
||||
void setParameterAtIndex(double f, int index) override;
|
||||
double parameterAtIndex(int index) override;
|
||||
double lowerBound() override;
|
||||
double lowerBound() override { return m_lowerBound; }
|
||||
private:
|
||||
void compute(int indexKnownElement) override;
|
||||
double m_lowerBound;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "calculation_cell.h"
|
||||
#include "responder_image_cell.h"
|
||||
#include "../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Probability {
|
||||
|
||||
@@ -66,7 +66,7 @@ CalculationController::CalculationController(Responder * parentResponder, InputE
|
||||
assert(calculation != nullptr);
|
||||
m_selectableTableView.setMargins(k_tableMargin);
|
||||
m_selectableTableView.setVerticalCellOverlap(0);
|
||||
m_selectableTableView.setShowsIndicators(false);
|
||||
m_selectableTableView.setDecoratorType(ScrollView::Decorator::Type::None);
|
||||
m_selectableTableView.setBackgroundColor(KDColorWhite);
|
||||
|
||||
|
||||
|
||||
@@ -22,8 +22,7 @@ CalculationTypeController::CalculationTypeController(Responder * parentResponder
|
||||
assert(m_calculation != nullptr);
|
||||
m_selectableTableView.setMargins(0);
|
||||
m_selectableTableView.setVerticalCellOverlap(0);
|
||||
m_selectableTableView.setShowsIndicators(false);
|
||||
m_selectableTableView.setColorsBackground(false);
|
||||
m_selectableTableView.setDecoratorType(ScrollView::Decorator::Type::None);
|
||||
}
|
||||
|
||||
View * CalculationTypeController::view() {
|
||||
|
||||
@@ -4,23 +4,6 @@
|
||||
|
||||
namespace Probability {
|
||||
|
||||
BinomialLaw::BinomialLaw() :
|
||||
TwoParameterLaw(20.0, 0.5)
|
||||
{
|
||||
}
|
||||
|
||||
I18n::Message BinomialLaw::title() {
|
||||
return I18n::Message::BinomialLaw;
|
||||
}
|
||||
|
||||
Law::Type BinomialLaw::type() const {
|
||||
return Type::Binomial;
|
||||
}
|
||||
|
||||
bool BinomialLaw::isContinuous() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
I18n::Message BinomialLaw::parameterNameAtIndex(int index) {
|
||||
assert(index >= 0 && index < 2);
|
||||
if (index == 0) {
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
namespace Probability {
|
||||
|
||||
class BinomialLaw : public TwoParameterLaw {
|
||||
class BinomialLaw final : public TwoParameterLaw {
|
||||
public:
|
||||
BinomialLaw();
|
||||
I18n::Message title() override;
|
||||
Type type() const override;
|
||||
bool isContinuous() const override;
|
||||
BinomialLaw() : TwoParameterLaw(20.0, 0.5) {}
|
||||
I18n::Message title() override { return I18n::Message::BinomialLaw; }
|
||||
Type type() const override { return Type::Binomial; }
|
||||
bool isContinuous() const override { return false; }
|
||||
float xMin() override;
|
||||
float yMin() override;
|
||||
float xMax() override;
|
||||
|
||||
@@ -1,41 +1,15 @@
|
||||
#include "exponential_law.h"
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
#include <float.h>
|
||||
#include <ion.h>
|
||||
|
||||
namespace Probability {
|
||||
|
||||
ExponentialLaw::ExponentialLaw() :
|
||||
OneParameterLaw(1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
I18n::Message ExponentialLaw::title() {
|
||||
return I18n::Message::ExponentialLaw;
|
||||
}
|
||||
|
||||
Law::Type ExponentialLaw::type() const {
|
||||
return Type::Exponential;
|
||||
}
|
||||
|
||||
bool ExponentialLaw::isContinuous() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
I18n::Message ExponentialLaw::parameterNameAtIndex(int index) {
|
||||
assert(index == 0);
|
||||
return I18n::Message::Lambda;
|
||||
}
|
||||
|
||||
I18n::Message ExponentialLaw::parameterDefinitionAtIndex(int index) {
|
||||
assert(index == 0);
|
||||
return I18n::Message::LambdaExponentialDefinition;
|
||||
}
|
||||
|
||||
float ExponentialLaw::xMin() {
|
||||
float max = xMax();
|
||||
return - k_displayLeftMarginRatio * max;
|
||||
return - k_displayLeftMarginRatio * xMax();
|
||||
}
|
||||
|
||||
float ExponentialLaw::yMin() {
|
||||
return -k_displayBottomMarginRatio * yMax();
|
||||
}
|
||||
|
||||
float ExponentialLaw::xMax() {
|
||||
@@ -44,11 +18,7 @@ float ExponentialLaw::xMax() {
|
||||
if (result <= 0.0f) {
|
||||
result = 1.0f;
|
||||
}
|
||||
return result*(1.0f+ k_displayRightMarginRatio);
|
||||
}
|
||||
|
||||
float ExponentialLaw::yMin() {
|
||||
return -k_displayBottomMarginRatio*yMax();
|
||||
return result * (1.0f + k_displayRightMarginRatio);
|
||||
}
|
||||
|
||||
float ExponentialLaw::yMax() {
|
||||
@@ -59,14 +29,14 @@ float ExponentialLaw::yMax() {
|
||||
if (result <= 0.0f) {
|
||||
result = 1.0f;
|
||||
}
|
||||
return result*(1.0f+ k_displayTopMarginRatio);
|
||||
return result * (1.0f + k_displayTopMarginRatio);
|
||||
}
|
||||
|
||||
float ExponentialLaw::evaluateAtAbscissa(float x) const {
|
||||
if (x < 0.0f) {
|
||||
return NAN;
|
||||
}
|
||||
return m_parameter1*std::exp(-m_parameter1*x);
|
||||
return m_parameter1 * std::exp(-m_parameter1 * x);
|
||||
}
|
||||
|
||||
bool ExponentialLaw::authorizedValueAtIndex(float x, int index) const {
|
||||
@@ -77,7 +47,7 @@ bool ExponentialLaw::authorizedValueAtIndex(float x, int index) const {
|
||||
}
|
||||
|
||||
double ExponentialLaw::cumulativeDistributiveFunctionAtAbscissa(double x) const {
|
||||
return 1.0 - std::exp((double)(-m_parameter1*x));
|
||||
return 1.0 - std::exp((double)(-m_parameter1 * x));
|
||||
}
|
||||
|
||||
double ExponentialLaw::cumulativeDistributiveInverseForProbability(double * probability) {
|
||||
|
||||
@@ -2,21 +2,28 @@
|
||||
#define PROBABILITE_EXPONENTIAL_LAW_H
|
||||
|
||||
#include "one_parameter_law.h"
|
||||
#include <assert.h>
|
||||
|
||||
namespace Probability {
|
||||
|
||||
class ExponentialLaw : public OneParameterLaw {
|
||||
class ExponentialLaw final : public OneParameterLaw {
|
||||
public:
|
||||
ExponentialLaw();
|
||||
I18n::Message title() override;
|
||||
Type type() const override;
|
||||
bool isContinuous() const override;
|
||||
ExponentialLaw() : OneParameterLaw(1.0f) {}
|
||||
I18n::Message title() override { return I18n::Message::ExponentialLaw; }
|
||||
Type type() const override { return Type::Exponential; }
|
||||
bool isContinuous() const override { return true; }
|
||||
float xMin() override;
|
||||
float yMin() override;
|
||||
float xMax() override;
|
||||
float yMax() override;
|
||||
I18n::Message parameterNameAtIndex(int index) override;
|
||||
I18n::Message parameterDefinitionAtIndex(int index) override;
|
||||
I18n::Message parameterNameAtIndex(int index) override {
|
||||
assert(index == 0);
|
||||
return I18n::Message::Lambda;
|
||||
}
|
||||
I18n::Message parameterDefinitionAtIndex(int index) override {
|
||||
assert(index == 0);
|
||||
return I18n::Message::LambdaExponentialDefinition;
|
||||
}
|
||||
float evaluateAtAbscissa(float x) const override;
|
||||
bool authorizedValueAtIndex(float x, int index) const override;
|
||||
double cumulativeDistributiveFunctionAtAbscissa(double x) const override;
|
||||
|
||||
@@ -4,13 +4,8 @@
|
||||
|
||||
namespace Probability {
|
||||
|
||||
Law::Law() :
|
||||
Shared::CurveViewRange()
|
||||
{
|
||||
}
|
||||
|
||||
float Law::xGridUnit() {
|
||||
return computeGridUnit(Axis::X, xMin(), xMax());
|
||||
return computeGridUnit(Axis::X, xMax() - xMin());
|
||||
}
|
||||
|
||||
double Law::cumulativeDistributiveFunctionAtAbscissa(double x) const {
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
#include <escher.h>
|
||||
#include "../../constant.h"
|
||||
#include "../../shared/curve_view_range.h"
|
||||
#include "../../i18n.h"
|
||||
#include <apps/i18n.h>
|
||||
|
||||
namespace Probability {
|
||||
|
||||
class Law : public Shared::CurveViewRange {
|
||||
public:
|
||||
Law();
|
||||
Law() : Shared::CurveViewRange() {}
|
||||
enum class Type : uint8_t{
|
||||
Binomial,
|
||||
Uniform,
|
||||
|
||||
@@ -7,57 +7,8 @@
|
||||
|
||||
namespace Probability {
|
||||
|
||||
NormalLaw::NormalLaw() :
|
||||
TwoParameterLaw(0.0f, 1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
I18n::Message NormalLaw::title() {
|
||||
return I18n::Message::NormalLaw;
|
||||
}
|
||||
|
||||
Law::Type NormalLaw::type() const {
|
||||
return Type::Normal;
|
||||
}
|
||||
|
||||
bool NormalLaw::isContinuous() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
I18n::Message NormalLaw::parameterNameAtIndex(int index) {
|
||||
assert(index >= 0 && index < 2);
|
||||
if (index == 0) {
|
||||
return I18n::Message::Mu;
|
||||
} else {
|
||||
return I18n::Message::Sigma;
|
||||
}
|
||||
}
|
||||
|
||||
I18n::Message NormalLaw::parameterDefinitionAtIndex(int index) {
|
||||
assert(index >= 0 && index < 2);
|
||||
if (index == 0) {
|
||||
return I18n::Message::MeanDefinition;
|
||||
} else {
|
||||
return I18n::Message::DeviationDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
float NormalLaw::xMin() {
|
||||
if (m_parameter2 == 0.0f) {
|
||||
return m_parameter1 - 1.0f;
|
||||
}
|
||||
return m_parameter1 - 5.0f*std::fabs(m_parameter2);
|
||||
}
|
||||
|
||||
float NormalLaw::xMax() {
|
||||
if (m_parameter2 == 0.0f) {
|
||||
return m_parameter1 + 1.0f;
|
||||
}
|
||||
return m_parameter1 + 5.0f*std::fabs(m_parameter2);
|
||||
}
|
||||
|
||||
float NormalLaw::yMin() {
|
||||
return -k_displayBottomMarginRatio*yMax();
|
||||
return - k_displayBottomMarginRatio * yMax();
|
||||
}
|
||||
|
||||
float NormalLaw::yMax() {
|
||||
@@ -66,14 +17,30 @@ float NormalLaw::yMax() {
|
||||
if (std::isnan(result) || result <= 0.0f) {
|
||||
result = 1.0f;
|
||||
}
|
||||
return result*(1.0f+ k_displayTopMarginRatio);
|
||||
return result * (1.0f + k_displayTopMarginRatio);
|
||||
}
|
||||
|
||||
I18n::Message NormalLaw::parameterNameAtIndex(int index) {
|
||||
if (index == 0) {
|
||||
return I18n::Message::Mu;
|
||||
}
|
||||
assert(index == 1);
|
||||
return I18n::Message::Sigma;
|
||||
}
|
||||
|
||||
I18n::Message NormalLaw::parameterDefinitionAtIndex(int index) {
|
||||
if (index == 0) {
|
||||
return I18n::Message::MeanDefinition;
|
||||
}
|
||||
assert(index == 1);
|
||||
return I18n::Message::DeviationDefinition;
|
||||
}
|
||||
|
||||
float NormalLaw::evaluateAtAbscissa(float x) const {
|
||||
if (m_parameter2 == 0.0f) {
|
||||
return NAN;
|
||||
}
|
||||
return (1.0f/(std::fabs(m_parameter2)*std::sqrt(2.0f*M_PI)))*std::exp(-0.5f*std::pow((x-m_parameter1)/m_parameter2,2));
|
||||
return (1.0f/(std::fabs(m_parameter2) * std::sqrt(2.0f * M_PI))) * std::exp(-0.5f * std::pow((x - m_parameter1)/m_parameter2, 2));
|
||||
}
|
||||
|
||||
bool NormalLaw::authorizedValueAtIndex(float x, int index) const {
|
||||
@@ -94,17 +61,17 @@ void NormalLaw::setParameterAtIndex(float f, int index) {
|
||||
}
|
||||
|
||||
double NormalLaw::cumulativeDistributiveFunctionAtAbscissa(double x) const {
|
||||
if (m_parameter2 == 0.0f) {
|
||||
if (m_parameter2 == 0.0f) {
|
||||
return NAN;
|
||||
}
|
||||
return standardNormalCumulativeDistributiveFunctionAtAbscissa((x-m_parameter1)/std::fabs(m_parameter2));
|
||||
}
|
||||
|
||||
double NormalLaw::cumulativeDistributiveInverseForProbability(double * probability) {
|
||||
if (m_parameter2 == 0.0f) {
|
||||
if (m_parameter2 == 0.0f) {
|
||||
return NAN;
|
||||
}
|
||||
return standardNormalCumulativeDistributiveInverseForProbability(*probability)*std::fabs(m_parameter2) + m_parameter1;
|
||||
return standardNormalCumulativeDistributiveInverseForProbability(*probability) * std::fabs(m_parameter2) + m_parameter1;
|
||||
}
|
||||
|
||||
double NormalLaw::standardNormalCumulativeDistributiveFunctionAtAbscissa(double abscissa) const {
|
||||
@@ -117,7 +84,7 @@ double NormalLaw::standardNormalCumulativeDistributiveFunctionAtAbscissa(double
|
||||
if (abscissa > k_boundStandardNormalDistribution) {
|
||||
return 1.0;
|
||||
}
|
||||
return 0.5+0.5*std::erf(abscissa/std::sqrt(2.0));
|
||||
return 0.5 + 0.5 * std::erf(abscissa/std::sqrt(2.0));
|
||||
}
|
||||
|
||||
double NormalLaw::standardNormalCumulativeDistributiveInverseForProbability(double probability) {
|
||||
@@ -130,7 +97,15 @@ double NormalLaw::standardNormalCumulativeDistributiveInverseForProbability(doub
|
||||
if (probability < 0.5) {
|
||||
return -standardNormalCumulativeDistributiveInverseForProbability(1-probability);
|
||||
}
|
||||
return std::sqrt(2.0)*erfInv(2.0*probability-1.0);
|
||||
return std::sqrt(2.0) * erfInv(2.0 * probability - 1.0);
|
||||
}
|
||||
|
||||
float NormalLaw::xExtremum(bool min) const {
|
||||
int coefficient = (min ? -1 : 1);
|
||||
if (m_parameter2 == 0.0f) {
|
||||
return m_parameter1 + coefficient * 1.0f;
|
||||
}
|
||||
return m_parameter1 + coefficient * 5.0f * std::fabs(m_parameter2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user