Compare commits

...

198 Commits

Author SHA1 Message Date
Quentin
651abf9c7b [Feature] Stay Home 2020-04-01 12:45:00 +02:00
Quentin
0b83604e3e [Update] Epsilon 13.2.0 2020-04-01 12:24:38 +02:00
Quentin
9b1add66a4 [Git] Fix conflicts 2020-04-01 12:23:52 +02:00
Quentin
15ecd45a76 [Fix] Compilation error 2020-04-01 12:14:06 +02:00
Quentin
0d56576f9c [Git] Fix conflicts 2020-04-01 11:36:16 +02:00
Léa Saviot
511a96f464 [apps/code] Add matplotlib.pyplot functions to the toolbox catalog
Not just in the modules submenu
2020-04-01 10:18:09 +02:00
Émilie Feral
0f00bdda33 [apps] Fix test build 2020-04-01 10:18:09 +02:00
Émilie Feral
244b97e89b [python] matplotlib: handle case plot([],[]) 2020-04-01 10:18:09 +02:00
Émilie Feral
e5660635d6 [python] matplotlib: handle case hist([]) 2020-04-01 10:18:09 +02:00
Émilie Feral
3987167419 [python] matplotlib: add comment 2020-04-01 10:18:09 +02:00
Émilie Feral
28224bd75e [python] matplotlib: fix hist implementation
This fixes the following crash: input 'hist([1,2,100],[1,2]) on a Python
console with matplotlib.pyplot imported
2020-04-01 10:18:09 +02:00
Émilie Feral
bc1eae17d7 [python] matplotlib: change text() relative position to be similar to
python3
2020-04-01 10:18:09 +02:00
Émilie Feral
642a7c7f61 [apps/code] Increase python heap to 32k 2020-04-01 10:18:09 +02:00
Émilie Feral
7c612f35a8 [python] matplotlib: change Store::Rectangle structure to (left, right,
top, bottom) and avoid rounding error when converting flaot rect to
pixel
2020-04-01 10:18:09 +02:00
Émilie Feral
d468f5e130 [python] WIP matplotlib: avoid empty pixel line between bars and axis
line
2020-04-01 10:18:09 +02:00
Émilie Feral
84bc46ca8c [python] matplotlib: PlotView: improve rect drawing (use round instead
of truncating pixelFloat
2020-04-01 10:18:09 +02:00
Émilie Feral
b3b6565410 [python] modpyplot: show() does nothing when the store is empty 2020-04-01 10:18:09 +02:00
Émilie Feral
ce33faad11 [python] matplotlib: PlotView: rectangle are always visible despite the
pixel width
2020-04-01 10:18:09 +02:00
Émilie Feral
51eabf08e1 [python] matplotlib: fix PlotStore::initRange for an only dot 2020-04-01 10:18:09 +02:00
Émilie Feral
2c82460470 [python] matplotlib: add a comment to PlotView 2020-04-01 10:18:09 +02:00
Émilie Feral
b290bed409 [python] matplotlib: fix typo in ErrorValue 2020-04-01 10:18:09 +02:00
Émilie Feral
d247843da6 [apps/code] Clean ConsoleController::reloadData (always returns true) 2020-04-01 10:18:09 +02:00
Émilie Feral
81284120af [apps/code] ConsoleController: refreshOutput is now done only when the
console is active
2020-04-01 10:18:09 +02:00
Émilie Feral
574eacb69c [python] matplotlib: flush heap memory when any error is raised 2020-04-01 10:18:09 +02:00
Léa Saviot
2f4064d92b [apps/code] Fix axis() command without arguments
It inserted axis(,,,) instead of axis()
2020-04-01 10:18:09 +02:00
Léa Saviot
2ac1396dd2 [apps/code] Put back the polynomial script 2020-04-01 10:18:09 +02:00
Léa Saviot
b2c95bcbbf [apps/code] Parabola script 2020-04-01 10:18:09 +02:00
Émilie Feral
61e7ec52e6 [python] matplotlib: make pyplot a submodule of matplotlib 2020-04-01 10:18:09 +02:00
Émilie Feral
7d5568ff1a [python] WIP: change change pyplot name: pyplot --> matplotlib.pyplot 2020-04-01 10:18:09 +02:00
Léa Saviot
399cfffc83 [apps/code] Fix toolbox texts 2020-04-01 10:18:09 +02:00
Léa Saviot
89ef6ec71b [apps/code] Add MatplotlibPyplot in the toolbox 2020-04-01 10:18:09 +02:00
Léa Saviot
f5e69395ee [apps/code] Reorder toolbox modules 2020-04-01 10:18:09 +02:00
Émilie Feral
1c4f43c665 [python] matplotlib: handle empty range histogram 2020-04-01 10:18:09 +02:00
Émilie Feral
1c714a6ee6 [python] matplotlib: PlotStore checks for type before accepting a new object
This fixes the crash: when a non-float value is added through the
tupple, the next float extraction will fail
2020-04-01 10:18:09 +02:00
Émilie Feral
6d10e9fdc2 [python] matplotlib: improve and fix arguments checking 2020-04-01 10:18:09 +02:00
Émilie Feral
bf7c3b1aab [python] matplotlib: implement "plot(y)' 2020-04-01 10:18:09 +02:00
Émilie Feral
dc58b9692f [python] matplotlib: imporve 'hist' 2020-04-01 10:18:09 +02:00
Émilie Feral
1895b83251 [python] Remove useless code 2020-04-01 10:18:09 +02:00
Émilie Feral
f97f56c021 [python] matplotlib: improve 'bar' arguments acceptation 2020-04-01 10:18:09 +02:00
Émilie Feral
18d59d923a [python] matplotlib: fix automatic range initialization 2020-04-01 10:18:09 +02:00
Émilie Feral
9a240bb0b4 [python] matplotlib: improve 'grid' 2020-04-01 10:18:09 +02:00
Émilie Feral
1b768ba34a [python] modpyplot: improve 'axis' arguments acceptance 2020-04-01 10:18:09 +02:00
Émilie Feral
81170610eb [python] Matplotlib: init store range depending on 'auto' parameter 2020-04-01 10:18:09 +02:00
Émilie Feral
8aa1930f80 [python] Matplotlib: handle 'auto' range computation 2020-04-01 10:18:09 +02:00
Émilie Feral
fb3f6ab6f3 [apps/code][python] ConsoleController doesn't keep any pointer/boolean to know
if the sandbox/matplotlib view controller is displayed. Its state won't be
always right; instead, use the StackViewController depth.

This fixes the following bug: when popping the sandbox/matplotlib view
controller, the first responder token was not given to the console
controller!
2020-04-01 10:18:09 +02:00
Émilie Feral
d0c5ac0343 [escher] StackViewController: add a method to return the
topViewController
2020-04-01 10:18:09 +02:00
Émilie Feral
15e5f7a285 [python] Matplotlib: reload labels in PlotController::viewWillAppear 2020-04-01 10:18:09 +02:00
Émilie Feral
89b54d424e [apps/code] ConsoleController: when becoming first responder, check if a
controller is displayed and switch the first responder accordingly
2020-04-01 10:18:09 +02:00
Émilie Feral
7e73afc654 [python] Matplotlib: flush the plot store when the controller is popped 2020-04-01 10:18:09 +02:00
Émilie Feral
24cd5079d4 [python] matplotlib: fix modpyplot_gc_collect 2020-04-01 10:18:08 +02:00
Émilie Feral
886fc98350 [escher] Palette: factorize data color iteration 2020-04-01 10:18:08 +02:00
Émilie Feral
c4847b22cc Coding style 2020-04-01 10:18:08 +02:00
Émilie Feral
bd3fa60594 [app/graph] Enables zoom on CalculationGraphControllers 2020-04-01 10:18:08 +02:00
Émilie Feral
4022cdfa60 [python] Matplotlib: plot_controller inherits from
ZoomAndPanCurveViewController to be able to pan
2020-04-01 10:18:08 +02:00
Émilie Feral
d504564334 [apps/shared] Create ZoomAndPanCurveViewController,
ZoomParameterController inherits from ZoomAndPanCurveViewController
2020-04-01 10:18:08 +02:00
Émilie Feral
52b6508d6c [apps/shared] Create ZoomCurveViewController:
SimpleInteractiveCurveViewController inherits from
ZoomCurveViewController
2020-04-01 10:18:08 +02:00
Émilie Feral
7d48d4e7c4 [apps/code] Console controller: display only one ExecutionViewController
at a time
2020-04-01 10:18:08 +02:00
Émilie Feral
53ec023ea0 [apps/code] ConsoleController: factorize code to reload the table 2020-04-01 10:18:08 +02:00
Émilie Feral
659da1dff8 [apps][python] ExecutionEnvironment handles hide sand display of sandbox
and plot controller the same way
2020-04-01 10:18:08 +02:00
Émilie Feral
51da01aa11 [apps/code] Remove 'm_preventEdition' from ConsoleController, it was
always used with m_preventEdition = true.
2020-04-01 10:18:08 +02:00
Émilie Feral
b5d3070ef5 [python] matplotlib: improve arrow method, draw arrow edge 2020-04-01 10:18:08 +02:00
Émilie Feral
9e822e85e5 [apps/shared] CurveView: implement drawArrow 2020-04-01 10:18:08 +02:00
Émilie Feral
70335b7a47 [python] matplotlib port: draft version of arrow method 2020-04-01 10:18:08 +02:00
Émilie Feral
bc8dc0c59c [apps] Use drawSegment when drawing lines instead of drawCurve or
drawCartesianCurve
2020-04-01 10:18:08 +02:00
Émilie Feral
aaf71328ba [apps/shared] CurveView: resolve name conflict -
drawHorizontalOrVerticalSegment & drawSegment -
2020-04-01 10:18:08 +02:00
Émilie Feral
7d60c6554e [python] matplotlib port: first version of hist method 2020-04-01 10:18:08 +02:00
Émilie Feral
c69ec608e8 [python] matplotlib: label are centered around their position 2020-04-01 10:18:08 +02:00
Émilie Feral
0ae81374d9 [python] matplotlib port: implement bar method 2020-04-01 10:18:08 +02:00
Émilie Feral
373a85f2b7 [python] matplotlib port: clean duplicate 2020-04-01 10:18:08 +02:00
Émilie Feral
da1c6090b5 [python] matplotlib port: factorize input validation 2020-04-01 10:18:08 +02:00
Romain Goyet
a0319905d7 [wip] Clean Rect and drawing 2020-04-01 10:18:08 +02:00
Romain Goyet
d71ad9b288 [wip] Convenience to test matplotlib 2020-04-01 10:18:08 +02:00
Romain Goyet
3df8018943 [apps/code] Remove useless code 2020-04-01 10:18:08 +02:00
Romain Goyet
a062c570d5 [python/matplotlib] Add grid control 2020-04-01 10:18:08 +02:00
Romain Goyet
a3b1b51f75 [pyton/matplotlib] Support plot 2020-04-01 10:18:08 +02:00
Romain Goyet
a6773ad73b [python/matplotlib] Add Text, simplify Dots 2020-04-01 10:18:08 +02:00
Romain Goyet
5ada80d03b [python/matplotlib] Add a Dot iterator 2020-04-01 10:18:08 +02:00
Romain Goyet
6f3d3f62de [python/matplotlib] Validate the plot parameters 2020-04-01 10:18:08 +02:00
Romain Goyet
6a796f5f7c [python] Add an "axis" function to the matplotlib module 2020-04-01 10:18:08 +02:00
Romain Goyet
c99bed6922 [python] Stub a matplotlib module 2020-04-01 10:18:08 +02:00
Romain Goyet
2b73c4c9aa [apps/code] Quick hacks to allow pushing a view controller 2020-04-01 10:18:08 +02:00
Romain Goyet
131df18b00 [python] A module can now ask to present a view controller 2020-04-01 10:18:08 +02:00
Quentin
735294b91b [Git] Fix conflicts 2020-04-01 00:17:17 +02:00
Léa Saviot
bd0b9f8a4a [apps/curve_view] Fix typo
The labels would not float on the right of the display
2020-03-31 15:16:39 +02:00
Léa Saviot
620ef3f570 [poincare] Use SymbolAbstract::hasSameNameAs 2020-03-31 13:42:42 +02:00
Léa Saviot
169d6bf94d [poincare/parametered_expression] Use parameter() 2020-03-31 13:42:42 +02:00
Léa Saviot
94fb5815f9 [poincare] Fix replaceReplaceableSymbols for parametered expressions
Scenario: ans*int(0,x,0,0)->x then cos(x) crashed because replaceReplaceableSymbols
would not care if it was replacing parameters in a parametered
expression
2020-03-31 13:42:42 +02:00
Léa Saviot
764cf1087a [apps/solver] Fix EquationStore::resolveLinearSystem
Scenario: solve a system with the maximum number of variables -> our
routine to compute the number of variables did not use
k_maxNumberOfVariables, so we ended up adding the same children to the
matrix Ab, which created ghosts, which made the deep reduction crash.
2020-03-31 12:05:38 +02:00
Émilie Feral
64c7688866 [.github] workflow: update to actions/checkout@v2 2020-03-31 11:37:59 +02:00
Quentin
bf9d365ee8 [Fix] GitHub Actions 2020-03-27 21:30:42 +01:00
Quentin
6c3261b356 [Git] Fix conflicts 2020-03-27 21:16:47 +01:00
Émilie Feral
b8b3829ea4 [ion] Web: enable to set environment variable 2020-03-27 09:32:31 -04:00
Romain Goyet
51b3a007e5 [ion/simulator/web] Remove old comment 2020-03-26 09:31:58 +01:00
Romain Goyet
df5c0752fb [escher] Remove a useless header 2020-03-26 09:31:58 +01:00
Romain Goyet
8bd01b600b [ion/simulator/web] Properly handle touch events 2020-03-26 09:31:58 +01:00
Émilie Feral
d950e37b22 [build] Emscripten toolchain: do not use a memory-init-file 2020-03-25 14:35:35 +01:00
Romain Goyet
64bab33792 [build] Add apk has a handy target on android 2020-03-25 13:44:10 +01:00
Romain Goyet
5e9543e3b7 Remove whitespace 2020-03-25 13:44:10 +01:00
Romain Goyet
2cdb5d38bf [build/android] Ignore the linter on release builds 2020-03-25 13:44:10 +01:00
Romain Goyet
b36de49b48 [simulator/android] Sign iff signing environment is provided 2020-03-25 13:44:10 +01:00
Romain Goyet
fca1dde44d [simulator/android] Use target-agnostic rules 2020-03-25 13:44:10 +01:00
Romain Goyet
693cff1e23 [build] Defining EXE is not required
Some platforms don't have direct executable formats. For instance, on
Android, there *is* an EXE format for a given ARCH, but .so does not
apply to ARCH-less builds.

And having default rules for %.so on ARCH-less Android would get in
the way when copying the shared obejcts for the APK.
2020-03-25 13:44:10 +01:00
Romain Goyet
964541d645 [build] Don't show any message if official tos have been accepted 2020-03-25 13:44:10 +01:00
Romain Goyet
625afcfd42 [build/android] Unify the behavior with iOS and macOS 2020-03-25 13:44:10 +01:00
Romain Goyet
46647cc35c [build] Allow building official targets on CI environments 2020-03-25 13:44:10 +01:00
Émilie Feral
3245a0060e [build] Fix target all_official: get rif of .mem 2020-03-24 16:44:20 +01:00
Émilie Feral
f84b3dc5c1 [poincare] Power approximation: avoid approximating a power to 0 when
one of the real/imaginary part was not null
2020-03-24 16:22:43 +01:00
Émilie Feral
7c79c70890 [poincare] When simplification has been interrupted, escape the end of
simplification. Otherwise we can be stuck in infinite loop.

This fixes the following bug: when simplifying an expression as
'bigRational1^x*bigRational2^x', we use the rule a^x*b^x --> (a¨b)^x. However,
in this case, a*b can't be reduce (resulting rational would be too big) and
we're stuck in the loop a^x*b^x --> (a¨b)^x --> a^x*b^x --> (a¨b)^x...
2020-03-24 16:22:43 +01:00
Émilie Feral
c0f73e97d2 [ion] Android Makefile: simplify rule_for_gradle 2020-03-24 10:26:59 -04:00
Émilie Feral
43bf89c6e4 [ion] Android build: specify libepsilon libraries' name when building
the apk
2020-03-24 10:26:59 -04:00
Romain Goyet
62324b9cac [build/emscripten] Don't use memory init files anymore
Those provide a really small size gain and are painful to deploy
2020-03-24 15:02:10 +01:00
Romain Goyet
ca89c06ffe [build/emscripten] We now use the newer #canvas convention 2020-03-24 15:02:10 +01:00
Romain Goyet
fd629de548 [build] Clean the "all" targets
Remove "DEBUG=0" because it's the default
Use handy targets when possible
2020-03-24 15:02:10 +01:00
Romain Goyet
eadfe4aa56 [ion/simulator/web] Name the target "epsilon.zip" to match other targets
This way it's consistent with epsilon.ipa on TARGET=ios and epsilon.apk
on TARGET=android
2020-03-24 15:02:10 +01:00
Romain Goyet
edbd879b4b [ion] Modularize the HTML simulator 2020-03-24 15:02:10 +01:00
Léa Saviot
05d24e0c61 [ion/android] Longer comment on Home button hiding fix 2020-03-24 10:10:02 +01:00
Léa Saviot
f31de20039 [ion/android] Hide the status bar and navigation buttons
This is a hack, we should find why this was broken after v12.
2020-03-24 10:10:02 +01:00
Quentin Guidée
3da284913d [Build] Increment Epsilon version 2020-03-23 10:35:46 +01:00
Quentin Guidée
06905c70e4 Merge remote-tracking branch 'upstream/master' into omega-hotfix 2020-03-21 11:42:39 +01:00
Quentin Guidée
ea796d9b51 Merge branch '0b101-fixedCompactCutoffBug2' into omega-hotfix 2020-03-20 22:04:46 +01:00
Émilie Feral
5f5636fe4d [build] Fix all_official target 2020-03-20 09:32:24 +01:00
Émilie Feral
1809037273 [ion] Fix epsilon.official.ipa dependencies 2020-03-19 13:36:10 +01:00
David
dab8880fbd Merge branch 'omega-hotfix' into fixedCompactCutoffBug2 2020-03-18 11:59:10 -05:00
David
c5b21cff71 [Fix] Compact cutoff bug 2020-03-18 11:56:48 -05:00
Romain Goyet
81cd18ad67 [build] Signing android apps is easier
Signing parameters can be passed on the command line, e.g. "ANDROID_SIGNING_STORE_FILE=foobar", or they can be written to a ~/.gradle/gradle.properties file using the "EPSILON_SIGNING_STORE_FILE=foobar" syntax.
2020-03-18 17:30:20 +01:00
Quentin Guidée
bfe2fc1a04 Merge remote-tracking branch 'upstream/master' into omega-hotfix 2020-03-17 20:59:23 +01:00
Émilie Feral
5f8f1d96ee [build] Actually use the mobileprovision file stored in build/artifacts/ 2020-03-16 18:07:01 +01:00
Émilie Feral
8c370b409c [build] Add the .mem files to all_official/ 2020-03-16 18:07:01 +01:00
Émilie Feral
d2f40130b2 [build] Change folder name: stable_release --> all_official 2020-03-16 18:07:01 +01:00
Jacob Young
a8783fe21f Remove a duplicate function, cleanup sorting and use consistent argument names in math.h.
Add missing math.h tests and make each test a single line for easier comparison with math.h.
Add missing cmath undefs and functions and use constexpr instead of static.
2020-03-16 15:00:40 +01:00
Léa Saviot
e828491171 [apps/probability] Test on finite integral computations 2020-03-16 11:40:40 +01:00
Léa Saviot
29b4c75227 [apps/probability] Assert discrete distributions override evaluation 2020-03-16 11:40:40 +01:00
Léa Saviot
5c70fdc7a6 [apps/probability] Handle a == b case in finite integral computation
For non continuous distributions, P(a <= X <= a) is not necessarily
null.
2020-03-16 11:40:40 +01:00
Émilie Feral
d222d13156 [poincare] CHange name PowerNode::tryComputeRealRootOfRationalPow -->
PowerNode::computeNotPrincipalRealRootOfRationalPow
2020-03-16 11:36:37 +01:00
Léa Saviot
da6306cb11 [poincare/multiplication] Interrupt reduction if overflow
When the overflow is due to the max size a rational can hold, stop the
reduction, otherwise some false results can appear.
For instance: 1.0092^50*ln(1.0092) was computed to 0 due to this problem
2020-03-13 14:16:43 +01:00
Léa Saviot
f00bd4d1c5 [poincare/multiplication] Factorize code 2020-03-13 14:16:43 +01:00
Léa Saviot
1e11650122 [poincare/test] Fix precision in approximation test 2020-03-13 14:16:43 +01:00
Léa Saviot
e636a2c315 [poincare/test] Add failing tests (commented but to fix later!) 2020-03-13 14:16:43 +01:00
Léa Saviot
313cbf6767 [poincare/arithmetic] Shortcut the LCM and GCD computation if equal
This fixes: LCM(7.88861e+169, 7.88861e+169), which overflowed at some
point during the computation
2020-03-13 14:16:43 +01:00
Léa Saviot
97d94d9e56 [poincare/test] Add failing test on multiplication simplification 2020-03-13 14:16:43 +01:00
LeaNumworks
13b2deb714 [poincare/approximation_helper] Clearer code
This should do the same output.
2020-03-12 14:41:50 +01:00
Léa Saviot
576d1dcd6b [poincare/power] Rename and comment computeRealRootOfRationalPow 2020-03-12 14:41:50 +01:00
Léa Saviot
175af27ea9 [poincare/approximation_helper] Factorize some code 2020-03-12 14:41:50 +01:00
Émilie Feral
879c1e3bf1 [poincare] ApproximationHelper: fix precision threshold of
NeglectRealOrImaginaryPartIfNeglectable
2020-03-12 14:41:50 +01:00
Émilie Feral
d431642e60 [poincare] Add tests on atanh approximation 2020-03-12 14:41:50 +01:00
Émilie Feral
a2e9d8efd6 [poincare] Improve trigonometry functions and power functions
approximations. We neglect the real or imaginary parts when it is
neglectable compared to the input.
2020-03-12 14:41:50 +01:00
Émilie Feral
9936d99411 [poincare] Add comment on Power::templatedApproximate 2020-03-12 14:41:50 +01:00
Émilie Feral
12a5f5499c [poincare] Handle real root finding in Power and NthRoot in order to
remove beautifying x^(p/q) -> root(x,q)^p. This triggered precision
loss!
2020-03-12 14:41:50 +01:00
Émilie Feral
5407709798 [poincare] Add approximation tests that fails because of precision loss 2020-03-12 14:41:50 +01:00
Émilie Feral
515405a5df [poincare] In Power::approximation and SquareRoot::approximation, the
real (or imaginary) part negligence should depend on the argument value
relatively to some other values (norms of the parameters) and not of its
value absolutely!
2020-03-12 14:41:50 +01:00
Quentin Guidée
eadcf0b6f9 Merge remote-tracking branch 'upstream/master' into omega-hotfix 2020-03-12 13:26:13 +01:00
Léa Saviot
ebdac63681 [poincare/parser] u_ v_ w_ are not special identifiers anymore 2020-03-12 11:48:54 +01:00
Quentin Guidée
d50511f1be [Fix] Fix conflicts 2020-03-11 19:12:20 +01:00
Léa Saviot
90f2e5beed [ion/sdl] Do not process more than one buffered event
Scenario:
Make an infinite loop script (while 1 : 1+1) and run it. Input 1234567
then press Back to interrupt the infinite loop -> the script execution
stops, then 1234567 is input in the input line, which is quite weird. It
is even weirder when the key pressed during the [script execution / a
long computation] result in navigation inside the calculator apps.
2020-03-11 15:36:52 +01:00
Léa Saviot
9ab3558cfe [ion/events_keyboard] Remove unused cases 2020-03-11 15:36:52 +01:00
Léa Saviot
1242258992 [ion] Handle key events in all simulators as in EPSILON_SDL_SCREEN_ONLY
This way, physical keyboard events can be caught by python on all
simulators
2020-03-11 15:36:52 +01:00
Léa Saviot
4a4ba52e38 [ion/events] Better handling of Shift on the web target 2020-03-11 15:36:52 +01:00
Léa Saviot
18f3054b50 [ion/simulator/web] Do not duplicate events in scan and getPlatformEvent
Some events were caught by bith scan() and getPlatformEvent()
2020-03-11 15:36:52 +01:00
Léa Saviot
a7d419c4bd [ion/emscripten] Get physical keyboard events in scan() 2020-03-11 15:36:52 +01:00
Léa Saviot
8168a125e6 [apps/statistics] Remove unused variable in HistogramView
It is unused as HistogramView now inherits Shared::HorizontallyLabeledCurveView
2020-03-11 13:58:41 +01:00
Léa Saviot
702772a7c9 [apps/reg] Store::m_seriesChecksum is Snapshot::m_prevModelsVersions
Share these objects instead of duplicating them
2020-03-11 11:43:36 +01:00
Léa Saviot
53705fb333 [apps/graph_ctrlr] Reload range if no previous model is present
We memoize the checksum of the x first models, and we check that one of
these models is still present when the graph view appears. If so, we do
not reload the range, other wise we reload it.

Scenario:
f(t) = [t^2  t+1] in parametric
Display the graph
f(x) = 1 on ]-inf;0]
g(x) = 2 on [0;inf[
Display the graph -> the range did not change
2020-03-11 11:43:36 +01:00
Léa Saviot
aab8974934 [apps] Memoize five model checksums 2020-03-11 11:43:36 +01:00
Romain Goyet
2bf83c43a8 [apps/shared] Factorize CurveView::label
There was a lot of code duplication.
I removed the initialization of xLabel{} and yLabels{} because those are
scratch buffers that shouldn't be accessed before being written to
anyway.
2020-03-11 09:51:33 +01:00
Quentin
8a27c81a83 Merge pull request #298 from M4xi1m3/omega-hotfix
Removed duplicate rule, deleted .gradle, added to gitignore.
2020-03-10 18:02:59 +01:00
Léa Saviot
ef249b0bdb [poincare/parser] parseSpecialId must go through one of the subcases
Otherwise we might go through the method without creating leftHandSide
2020-03-10 11:35:37 +01:00
Léa Saviot
79f3ee43bc [poincare/parser] log_ is not a special identifier anymore
The change was made a few commits ago, but this was forgotten
2020-03-10 11:35:37 +01:00
Ruben Dashyan
1ca902c129 [apps/shared/round_cursor_view] Comment about markRectAsDirty 2020-03-10 11:11:57 +01:00
Ruben Dashyan
037fa088e9 [escher/transparent_view] markRectAsDirty is protected
as it is in View.
2020-03-10 11:11:57 +01:00
Ruben Dashyan
d64e58b9dc [escher/transparent_view] Remove redundancy 2020-03-10 11:11:57 +01:00
Ruben Dashyan
8337e36f46 [apps/shared/*_cursor_view] CursorView inherits from TransparentView
so that CursorView tells its superview to redrawn in the background,
except the RoundCursorView.
2020-03-10 11:11:57 +01:00
Ruben Dashyan
ed98218e7b [poincare/grid_layout] Explicit the making of a protected member as public 2020-03-10 10:33:30 +01:00
Ruben Dashyan
aa4a33d849 [poincare/layout_node] Remove unused method 2020-03-10 10:33:30 +01:00
Ruben Dashyan
afb1d18d65 [apps/shared/sum_graph_controller] Factor constexpr 2020-03-10 10:33:30 +01:00
Ruben Dashyan
f0ef84b3bc [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor Layout building 2020-03-10 10:33:30 +01:00
Ruben Dashyan
55bb3f677a [apps/shared/sum_graph_controller] In LegendView::setSumLayout, simplify equal sign 2020-03-10 10:33:30 +01:00
Ruben Dashyan
0a92579571 [apps/shared/sum_graph_controller] Fix variable type 2020-03-10 10:33:30 +01:00
Ruben Dashyan
04794dd26f [apps/shared/sum_graph_controller] Uniformize number of significant digits 2020-03-10 10:33:30 +01:00
Ruben Dashyan
7ee8c31c70 [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor sum symbol layout 2020-03-10 10:33:30 +01:00
Ruben Dashyan
24fa8b28a9 [apps/shared/sum_graph_controller] In LegendView::setSumLayout, factor m_sum.setAlignment 2020-03-10 10:33:30 +01:00
Ruben Dashyan
6b527d3b00 [apps/shared/sum_graph_controller] Rename setSumSymbol to setSumLayout 2020-03-10 10:33:30 +01:00
Ruben Dashyan
e1624c79aa [apps/shared/sum_graph_controller] Class doesn't need to hold m_sumLayout 2020-03-10 10:33:30 +01:00
Ruben Dashyan
7a633b1e75 [apps/sequence/sequence] SequenceModel's name method need not be virtual 2020-03-10 10:33:30 +01:00
Ruben Dashyan
fccd72b757 [apps/sequence/sequence] Do not memoize nameLayout
Fixes the following bug:
In the graph tab of the Sequence app, compute the sum of the terms of
a sequence from 1 to 9 and then from 1 to 10. The Layout is memoized
after the first time and mispositioned the second time since it is
not recomputed.
2020-03-10 10:33:30 +01:00
Romain Goyet
c1215063ee Small fixes to the documentation 2020-03-10 10:26:49 +01:00
Léa Saviot
cf84a30768 [poincare/absolute_value] ShallowReduce done in double, not float
This fixes abs(-2.3*10^-39) that returned a negative value
2020-03-10 10:23:33 +01:00
David
ad672f9111 [Fix] Display bug where "x=a(x)" got cutoff 2020-03-09 21:44:22 +01:00
David
d1c8d6f11c Fixed display bug where "x=a(x)" got cutoff 2020-03-09 15:38:24 -05:00
Léa Saviot
5ca6b7dbf8 [poincare/code_point_layout] Fix collapsing
Scenario: Enter "(12/34 * 10)" then press "Divide" -> the numerator of
the division was not the whole parenthesed expression
2020-03-09 16:41:58 +01:00
Quentin Guidée
bd6f30fda5 Merge remote-tracking branch 'upstream/master' into omega-hotfix 2020-03-06 16:06:39 +01:00
Léa Saviot
1dc6e77049 [poincare/matrix] Forbid nested matrices
Scenario: in calculation,
1/matrix(matrix(matrix(matrix(... matrix(1) ... )))) gave kind of a
weird result. These kind of computations also broke the fuzzer.
2020-03-04 16:21:25 +01:00
redgl0w
dfe51df321 Updated the month definition 2020-03-04 10:08:44 +01:00
redgl0w
035a0377bd Updated the month definition 2020-03-04 10:08:44 +01:00
Léa Saviot
4f76e4418f [apps/console_edit_cell] Fix input result copying 2020-03-02 17:24:54 +01:00
Léa Saviot
a06660ee25 [poincare/vert_off_lay] Subscript layout serializes without _
This way there is no parsing confusion when copy pasting the subscript of
a subscript layout
2020-03-02 09:55:11 +01:00
Neven Sajko
aae5e49c01 Remove useless uses of const for return types
An integer or float value can not be assigned to, so there is no point
in qualifying it as const.
2020-03-02 09:48:23 +01:00
M4x1m3
8a4e9520f3 Removed .gradle, added it to gitignore. 2020-03-01 16:48:36 +01:00
M4x1m3
175e38711e Removed duplicate binpack rule. 2020-03-01 16:45:53 +01:00
200 changed files with 2900 additions and 1237 deletions

View File

@@ -66,7 +66,7 @@ jobs:
- uses: actions/upload-artifact@master
with:
name: epsilon-simulator-web.zip
path: output/release/simulator/web/simulator.zip
path: output/release/simulator/web/epsilon.zip
- run: make -j2 PLATFORM=simulator TARGET=web test.headless.js
build-simulator-linux:
runs-on: ubuntu-latest

3
.gitignore vendored
View File

@@ -3,4 +3,5 @@
build/device/**/*.pyc
epsilon.elf
.vscode
.DS_Store
.DS_Store
.gradle

View File

@@ -16,7 +16,7 @@ Omega is a fork of Numworks' Epsilon, the OS that runs on their calculator, whic
- An app for RPN
- A periodic table app + all of the molar masses for the elements in the toolbox
- More steps for brightness (16 instead of 5)
- 32 KB Python heap instead of 16 KB
- ~~32 KB Python heap instead of 16 KB~~ Now available on Epsilon `>=13.2.0`!
- And more...
The main new features are listed [here](https://github.com/Omega-Numworks/Omega/wiki/Main-features), and the complete changelog can be found [here](https://github.com/quentinguidee/Omega/wiki/Complete-changelog).

View File

@@ -6,7 +6,7 @@ using namespace Poincare;
namespace Calculation {
ComplexGraphView::ComplexGraphView(ComplexModel * complexModel) :
CurveView(complexModel),
LabeledCurveView(complexModel),
m_complex(complexModel)
{
}
@@ -24,13 +24,8 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
float imag = m_complex->imag();
assert(!std::isnan(real) && !std::isnan(imag) && !std::isinf(real) && !std::isinf(imag));
/* Draw the segment from the origin to the dot (real, imag) of equation
* x(t) = t*real and y(t) = t*imag with t in [0,1] */
drawCurve(ctx, rect, 0.0f, 1.0f, 0.01f,
[](float t, void * model, void * context) {
ComplexModel * complexModel = (ComplexModel *)model;
return Poincare::Coordinate2D<float>(complexModel->real()*t, complexModel->imag()*t);
}, m_complex, nullptr, false, Palette::GreyDark, false);
// Draw the segment from the origin to the dot (real, imag)
drawSegment(ctx, rect, 0.0f, 0.0f, m_complex->real(), m_complex->imag(), Palette::GreyDark, false);
/* Draw the partial ellipse indicating the angle θ
* - the ellipse parameters are a = |real|/5 and b = |imag|/5,
@@ -66,8 +61,8 @@ void ComplexGraphView::drawRect(KDContext * ctx, KDRect rect) const {
}, &parameters, &th, false, Palette::GreyDark, false);
// Draw dashed segment to indicate real and imaginary
drawSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3);
drawSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, real, 0.0f, imag, Palette::Red, 1, 3);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, imag, 0.0f, real, Palette::Red, 1, 3);
// Draw complex position on the plan
drawDot(ctx, rect, real, imag, Palette::Red, Size::Large);

View File

@@ -1,24 +1,19 @@
#ifndef CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_GRAPH_CELL_H
#define CALCULATION_ADDITIONAL_OUTPUTS_COMPLEX_GRAPH_CELL_H
#include "../../shared/curve_view.h"
#include "../../shared/labeled_curve_view.h"
#include "complex_model.h"
#include "illustration_cell.h"
namespace Calculation {
class ComplexGraphView : public Shared::CurveView {
class ComplexGraphView : public Shared::LabeledCurveView {
public:
ComplexGraphView(ComplexModel * complexModel);
void drawRect(KDContext * ctx, KDRect rect) const override;
private:
char * label(Axis axis, int index) const override {
return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]);
}
// '-' + significant digits + ".E-" + 2 digits (the represented dot is a float, so it is bounded by 1E38 and 1E-38
size_t labelMaxGlyphLengthSize() const override { return 1 + Poincare::Preferences::VeryShortNumberOfSignificantDigits + 3 + 2; }
char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
ComplexModel * m_complex;
};

View File

@@ -22,8 +22,8 @@ void TrigonometryGraphView::drawRect(KDContext * ctx, KDRect rect) const {
return Poincare::Coordinate2D<float>(std::cos(t), std::sin(t));
}, nullptr, nullptr, true, Palette::GreyDark, false);
// Draw dashed segment to indicate sine and cosine
drawSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::Red, 1, 3);
drawSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::Red, 1, 3);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, c, 0.0f, s, Palette::Red, 1, 3);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, s, 0.0f, c, Palette::Red, 1, 3);
// Draw angle position on the circle
drawDot(ctx, rect, c, s, Palette::Red, Size::Large);
// Draw graduations

View File

@@ -12,7 +12,6 @@ public:
TrigonometryGraphView(TrigonometryModel * model);
void drawRect(KDContext * ctx, KDRect rect) const override;
private:
char * label(Axis axis, int index) const override { return nullptr; }
TrigonometryModel * m_model;
};

View File

@@ -164,7 +164,7 @@ KDCoordinate Calculation::height(Context * context, bool expanded, bool allExpre
singleLine = exactOutputWidth + inputWidth < maxWidth - 40;
if (singleLine && Poincare::Preferences::sharedPreferences()->resultDisplay() == Poincare::Preferences::ResultDisplay::Compact && !allExpressionsInline) {
KDCoordinate exactOutputBaseline = exactLayout.baseline();
result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline);
result = maxCoordinate(inputBaseline, exactOutputBaseline) + maxCoordinate(inputHeight - inputBaseline, exactOutputHeight-exactOutputBaseline) + singleMargin;
} else {
if (allExpressionsInline) {
KDCoordinate exactOutputBaseline = exactLayout.baseline();

View File

@@ -13,12 +13,15 @@ PythonAbs = "Absolute/r Wert/Größe"
PythonAcos = "Arkuskosinus"
PythonAcosh = "Hyperbelkosinus"
PythonAppend = "Hängt x an das Ende der Liste"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
PythonAsin = "Arkussinus"
PythonAsinh = "Hyperbelsinus"
PythonAtan = "Arkustangens"
PythonAtan2 = "Gib atan(y/x)"
PythonAtanh = "Hyperbeltangens"
PythonBin = "Ganzzahl nach binär"
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values"
PythonBin = "Ganzzahl nach binär konvertieren"
PythonCeil = "Aufrundung"
PythonChoice = "Zufallszahl aus der Liste"
PythonClear = "Leere die Liste"
@@ -46,12 +49,15 @@ PythonFrExp = "Rest und Exponent von x"
PythonGamma = "Gammafunktion"
PythonGetPixel = "Farbe von Pixel (x,y)"
PythonGetrandbits = "Ganzzahl mit k zufälligen Bits"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Ganzzahl zu Hexadecimal"
PythonHist = "Draw the histogram of x"
PythonImportCmath = "cmath Modul importieren"
PythonImportIon = "ion Modul importieren"
PythonImportKandinsky = "kandinsky Modul importieren"
PythonImportRandom = "random Modul importieren"
PythonImportMath = "math Modul importieren"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
PythonImportTime = "time Modul importieren"
PythonImportTurtle = "turtle Modul importieren"
PythonIndex = "Index, bei dem x zuerst vorkommt"
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
PythonLog10 = "Logarithm to base 10"
PythonLog2 = "Logarithm to base 2"
PythonMathFunction = "math module function prefix"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractional and integer parts of x"
PythonMonotonic = "Value of a monotonic clock"
PythonOct = "Convert integer to octal"
PythonPhase = "Phase of z"
PythonPlot = "Plot y versus x as lines"
PythonPolar = "z in polar coordinates"
PythonPop = "Remove and return the last item"
PythonPower = "x raised to the power y"
@@ -138,9 +146,11 @@ PythonRect = "z in cartesian coordinates"
PythonRemove = "Remove the first occurrence of x"
PythonReverse = "Reverse the elements of the list"
PythonRound = "Round to n digits"
PythonScatter = "Draw a scatter plot of y versus x"
PythonSeed = "Initialize random number generator"
PythonSetPixel = "Color pixel (x,y)"
PythonSin = "Sinus"
PythonShow = "Display the figure"
PythonSin = "Sine"
PythonSinh = "Hyperbolic sine"
PythonSleep = "Suspend the execution for t seconds"
PythonSort = "Sort the list"
@@ -148,6 +158,7 @@ PythonSqrt = "Wurzel"
PythonSum = "Sum the items of a list"
PythonTan = "Tangens"
PythonTanh = "Hyperbolic tangent"
PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module function prefix"
PythonTrunc = "x truncated to an integer"
PythonTurtleBackward = "Move backward by x pixels"

View File

@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
PythonAcos = "Arc cosine"
PythonAcosh = "Arc hyperbolic cosine"
PythonAppend = "Add x to the end of the list"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
PythonAsin = "Arc sine"
PythonAsinh = "Arc hyperbolic sine"
PythonAtan = "Arc tangent"
PythonAtan2 = "Return atan(y/x)"
PythonAtanh = "Arc hyperbolic tangent"
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values"
PythonBin = "Convert integer to binary"
PythonCeil = "Ceiling"
PythonChoice = "Random number in the list"
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
PythonGamma = "Gamma function"
PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Convert integer to hexadecimal"
PythonHist = "Draw the histogram of x"
PythonImportCmath = "Import cmath module"
PythonImportIon = "Import ion module"
PythonImportKandinsky = "Import kandinsky module"
PythonImportRandom = "Import random module"
PythonImportMath = "Import math module"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
PythonImportTime = "Import time module"
PythonImportTurtle = "Import turtle module"
PythonIndex = "Index of the first x occurrence"
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
PythonLog10 = "Logarithm to base 10"
PythonLog2 = "Logarithm to base 2"
PythonMathFunction = "math module function prefix"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractional and integer parts of x"
PythonMonotonic = "Value of a monotonic clock"
PythonOct = "Convert integer to octal"
PythonPhase = "Phase of z"
PythonPlot = "Plot y versus x as lines"
PythonPolar = "z in polar coordinates"
PythonPop = "Remove and return the last item"
PythonPower = "x raised to the power y"
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
PythonRemove = "Remove the first occurrence of x"
PythonReverse = "Reverse the elements of the list"
PythonRound = "Round to n digits"
PythonScatter = "Draw a scatter plot of y versus x"
PythonSeed = "Initialize random number generator"
PythonSetPixel = "Color pixel (x,y)"
PythonShow = "Display the figure"
PythonSin = "Sine"
PythonSinh = "Hyperbolic sine"
PythonSleep = "Suspend the execution for t seconds"
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
PythonSum = "Sum the items of a list"
PythonTan = "Tangent"
PythonTanh = "Hyperbolic tangent"
PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module function prefix"
PythonTrunc = "x truncated to an integer"
PythonTurtleBackward = "Move backward by x pixels"

View File

@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
PythonAcos = "Arc cosine"
PythonAcosh = "Arc hyperbolic cosine"
PythonAppend = "Add x to the end of the list"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
PythonAsin = "Arc sine"
PythonAsinh = "Arc hyperbolic sine"
PythonAtan = "Arc tangent"
PythonAtan2 = "Return atan(y/x)"
PythonAtanh = "Arc hyperbolic tangent"
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values"
PythonBin = "Convert integer to binary"
PythonCeil = "Ceiling"
PythonChoice = "Random number in the list"
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
PythonGamma = "Gamma function"
PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Convert integer to hexadecimal"
PythonHist = "Draw the histogram of x"
PythonImportCmath = "Import cmath module"
PythonImportIon = "Import ion module"
PythonImportKandinsky = "Import kandinsky module"
PythonImportRandom = "Import random module"
PythonImportMath = "Import math module"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
PythonImportTime = "Import time module"
PythonImportTurtle = "Import turtle module"
PythonIndex = "Index of the first x occurrence"
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
PythonLog10 = "Logarithm to base 10"
PythonLog2 = "Logarithm to base 2"
PythonMathFunction = "math module function prefix"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractional and integer parts of x"
PythonMonotonic = "Value of a monotonic clock"
PythonOct = "Convert integer to octal"
PythonPhase = "Phase of z"
PythonPlot = "Plot y versus x as lines"
PythonPolar = "z in polar coordinates"
PythonPop = "Remove and return the last item"
PythonPower = "x raised to the power y"
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
PythonRemove = "Remove the first occurrence of x"
PythonReverse = "Reverse the elements of the list"
PythonRound = "Round to n digits"
PythonScatter = "Draw a scatter plot of y versus x"
PythonSeed = "Initialize random number generator"
PythonSetPixel = "Color pixel (x,y)"
PythonShow = "Display the figure"
PythonSin = "Sine"
PythonSinh = "Hyperbolic sine"
PythonSleep = "Suspend the execution for t seconds"
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
PythonSum = "Sum the items of a list"
PythonTan = "Tangent"
PythonTanh = "Hyperbolic tangent"
PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module function prefix"
PythonTrunc = "x truncated to an integer"
PythonTurtleBackward = "Move backward by x pixels"

View File

@@ -13,11 +13,14 @@ PythonAbs = "Valeur absolue/Module"
PythonAcos = "Arc cosinus"
PythonAcosh = "Arc cosinus hyperbolique"
PythonAppend = "Insère x à la fin de la liste"
PythonArrow = "Flèche de (x,y) à (x+dx,y+dy)"
PythonAsin = "Arc sinus"
PythonAsinh = "Arc sinus hyperbolique"
PythonAtan = "Arc tangente"
PythonAtan2 = "Calcul de atan(y/x)"
PythonAtanh = "Arc tangente hyperbolique"
PythonAxis = "Met les axes (xmin,xmax,ymin,ymax)"
PythonBar = "Diagramme en barres de la liste x"
PythonBin = "Conversion d'un entier en binaire"
PythonCeil = "Plafond"
PythonChoice = "Nombre aléatoire dans la liste"
@@ -46,12 +49,15 @@ PythonFrExp = "Mantisse et exposant de x : (m,e)"
PythonGamma = "Fonction gamma"
PythonGetPixel = "Renvoie la couleur du pixel (x,y)"
PythonGetrandbits = "Nombre aléatoire sur k bits"
PythonGrid = "Affiche ou masque la grille"
PythonHex = "Conversion entier en hexadécimal"
PythonHist = "Histogramme de la liste x"
PythonImportCmath = "Importation du module cmath"
PythonImportIon = "Importation du module ion"
PythonImportKandinsky = "Importation du module kandinsky"
PythonImportRandom = "Importation du module random"
PythonImportMath = "Importation du module math"
PythonImportMatplotlibPyplot = "Importation de matplotlib.pyplot"
PythonImportTurtle = "Importation du module turtle"
PythonImportTime = "Importation du module time"
PythonIndex = "Indice première occurrence de x"
@@ -117,12 +123,14 @@ PythonLog = "Logarithme de base a"
PythonLog10 = "Logarithme décimal"
PythonLog2 = "Logarithme de base 2"
PythonMathFunction = "Préfixe fonction du module math"
PythonMatplotlibPyplotFunction = "Préfixe du module matplotlib.pyplot"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Parties fractionnaire et entière"
PythonMonotonic = "Renvoie la valeur de l'horloge"
PythonOct = "Conversion en octal"
PythonPhase = "Argument de z"
PythonPlot = "Trace y en fonction de x"
PythonPolar = "Conversion en polaire"
PythonPop = "Supprime le dernier élément"
PythonPower = "x à la puissance y"
@@ -138,8 +146,10 @@ PythonRect = "Conversion en algébrique"
PythonRemove = "Supprime le premier x de la liste"
PythonReverse = "Inverse les éléments de la liste"
PythonRound = "Arrondi à n décimales"
PythonScatter = "Nuage des points (x,y)"
PythonSeed = "Initialiser générateur aléatoire"
PythonSetPixel = "Colore le pixel (x,y)"
PythonShow = "Affiche la figure"
PythonSin = "Sinus"
PythonSinh = "Sinus hyperbolique"
PythonSleep = "Suspend l'exécution t secondes"
@@ -148,6 +158,7 @@ PythonSqrt = "Racine carrée"
PythonSum = "Somme des éléments de la liste"
PythonTan = "Tangente"
PythonTanh = "Tangente hyperbolique"
PythonText = "Affiche un texte en (x,y)"
PythonTimeFunction = "Préfixe fonction module time"
PythonTrunc = "Troncature entière"
PythonTurtleBackward = "Recule de x pixels"

View File

@@ -13,11 +13,14 @@ PythonAbs = "Abszolút érték / nagyság"
PythonAcos = "Arc koszinusz"
PythonAcosh = "Íves hiperbolikus koszinusz"
PythonAppend = "x hozzáadása a lista végéhez"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
PythonAsin = "Arc szinusz"
PythonAsinh = "Íves hiperbolikus szinusz"
PythonAtan = "Arc érintö"
PythonAtan2 = "Visszatérés atan (y / x)"
PythonAtanh = "Arc hiperbolikus érintö"
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values"
PythonBin = "Egész szám konvertálása binárisra"
PythonCeil = "Mennyezet"
PythonChoice = "Véletlenszerü szám a listában"
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa és az x exponense"
PythonGamma = "Gamma funkció"
PythonGetPixel = "Visszatérési pixel (x, y) szín"
PythonGetrandbits = "Egész szám k véletlen bittel"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Egész szám konvertálása hexadecimálisra"
PythonHist = "Draw the histogram of x"
PythonImportCmath = "cmath modul importálása"
PythonImportIon = "Ion modul importálása"
PythonImportKandinsky = "Kandinsky modul importálása"
PythonImportRandom = "Véletlenszerü modul importálása"
PythonImportMath = "Import matematikai modul"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
PythonImportTime = "Idömodul importálása"
PythonImportTurtle = "Import teknös modul"
PythonIndex = "Az elsö x esemény indexe"
@@ -117,12 +123,14 @@ PythonLog = "Logaritmus az alap"
PythonLog10 = "Logaritmus az alaphoz 10"
PythonLog2 = "Logaritmus az alaphoz 2"
PythonMathFunction = "matematikai modul funkció elötag"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Az x tört és egész részei"
PythonMonotonic = "A monoton óra értéke"
PythonOct = "Egész szám konvertálása oktális értékre"
PythonPhase = "z fázis"
PythonPlot = "Plot y versus x as lines"
PythonPolar = "z poláris koordinátákban"
PythonPop = "Az utolsó elem eltávolítása és visszaküldése"
PythonPower = "x emelve az y teljesítményre"
@@ -138,8 +146,10 @@ PythonRect = "z derékszögü koordinátákban"
PythonRemove = "Távolítsa el az x elsö elöfordulását"
PythonReverse = "A lista elemeinek megfordítása"
PythonRound = "N számjegyre kerekítve"
PythonScatter = "Draw a scatter plot of y versus x"
PythonSeed = "Inicializálja a véletlenszám-generátort"
PythonSetPixel = "Színes pixel (x, y)"
PythonShow = "Display the figure"
PythonSin = "Sine"
PythonSinh = "Hiperbolikus szinusz"
PythonSleep = "A végrehajtás felfüggesztése t másodpercre"
@@ -148,6 +158,7 @@ PythonSqrt = "Négyzetgyök"
PythonSum = "Összegzi a lista elemeit"
PythonTan = "Érintö"
PythonTanh = "Hiperbolikus érintö"
PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "idömodul funkció elötag"
PythonTrunc = "x egészre csonkítva"
PythonTurtleBackward = "Visszalépés x pixelrel"

View File

@@ -13,11 +13,14 @@ PythonAbs = "Absolute value/Magnitude"
PythonAcos = "Arc cosine"
PythonAcosh = "Arc hyperbolic cosine"
PythonAppend = "Add x to the end of the list"
PythonArrow = "Arrow from (x,y) to (x+dx,y+dy)"
PythonAsin = "Arc sine"
PythonAsinh = "Arc hyperbolic sine"
PythonAtan = "Arc tangent"
PythonAtan2 = "Return atan(y/x)"
PythonAtanh = "Arc hyperbolic tangent"
PythonAxis = "Set axes to (xmin,xmax,ymin,ymax)"
PythonBar = "Draw a bar plot with x values"
PythonBin = "Convert integer to binary"
PythonCeil = "Ceiling"
PythonChoice = "Random number in the list"
@@ -46,12 +49,15 @@ PythonFrExp = "Mantissa and exponent of x"
PythonGamma = "Gamma function"
PythonGetPixel = "Return pixel (x,y) color"
PythonGetrandbits = "Integer with k random bits"
PythonGrid = "Toggle the visibility of the grid"
PythonHex = "Convert integer to hexadecimal"
PythonHist = "Draw the histogram of x"
PythonImportCmath = "Import cmath module"
PythonImportIon = "Import ion module"
PythonImportKandinsky = "Import kandinsky module"
PythonImportRandom = "Import random module"
PythonImportMath = "Import math module"
PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module"
PythonImportTime = "Import time module"
PythonImportTurtle = "Import turtle module"
PythonIndex = "Index of the first x occurrence"
@@ -117,12 +123,14 @@ PythonLog = "Logarithm to base a"
PythonLog10 = "Logarithm to base 10"
PythonLog2 = "Logarithm to base 2"
PythonMathFunction = "math module function prefix"
PythonMatplotlibPyplotFunction = "matplotlib.pyplot module prefix"
PythonMax = "Maximum"
PythonMin = "Minimum"
PythonModf = "Fractional and integer parts of x"
PythonMonotonic = "Value of a monotonic clock"
PythonOct = "Convert integer to octal"
PythonPhase = "Phase of z"
PythonPlot = "Plot y versus x as lines"
PythonPolar = "z in polar coordinates"
PythonPop = "Remove and return the last item"
PythonPower = "x raised to the power y"
@@ -138,8 +146,10 @@ PythonRect = "z in cartesian coordinates"
PythonRemove = "Remove the first occurrence of x"
PythonReverse = "Reverse the elements of the list"
PythonRound = "Round to n digits"
PythonScatter = "Draw a scatter plot of y versus x"
PythonSeed = "Initialize random number generator"
PythonSetPixel = "Color pixel (x,y)"
PythonShow = "Display the figure"
PythonSin = "Sine"
PythonSinh = "Hyperbolic sine"
PythonSleep = "Suspend the execution for t seconds"
@@ -148,6 +158,7 @@ PythonSqrt = "Square root"
PythonSum = "Sum the items of a list"
PythonTan = "Tangent"
PythonTanh = "Hyperbolic tangent"
PythonText = "Display a text at (x,y) coordinates"
PythonTimeFunction = "time module function prefix"
PythonTrunc = "x truncated to an integer"
PythonTurtleBackward = "Move backward by x pixels"

View File

@@ -12,11 +12,15 @@ PythonCommandAcos = "acos(x)"
PythonCommandAcosh = "acosh(x)"
PythonCommandAppend = "list.append(x)"
PythonCommandAppendWithoutArg = ".append(\x11)"
PythonCommandArrow = "arrow(x,y,dx,dy)"
PythonCommandAsin = "asin(x)"
PythonCommandAsinh = "asinh(x)"
PythonCommandAtan = "atan(x)"
PythonCommandAtan2 = "atan2(y,x)"
PythonCommandAtanh = "atanh(x)"
PythonCommandAxis = "axis((xmin,xmax,ymin,ymax))"
PythonCommandAxisWithoutArg = "axis(\x11)"
PythonCommandBar = "bar(x,height)"
PythonCommandBin = "bin(x)"
PythonCommandCeil = "ceil(x)"
PythonCommandChoice = "choice(list)"
@@ -52,13 +56,16 @@ PythonCommandFrExp = "frexp(x)"
PythonCommandGamma = "gamma(x)"
PythonCommandGetPixel = "get_pixel(x,y)"
PythonCommandGetrandbits = "getrandbits(k)"
PythonCommandGrid = "grid()"
PythonCommandHex = "hex(x)"
PythonCommandHist = "hist(x,bins)"
PythonCommandImag = "z.imag"
PythonCommandImagWithoutArg = ".imag"
PythonCommandImportFromCmath = "from cmath import *"
PythonCommandImportFromIon = "from ion import *"
PythonCommandImportFromKandinsky = "from kandinsky import *"
PythonCommandImportFromMath = "from math import *"
PythonCommandImportFromMatplotlibPyplot = "from matplotlib.pyplot import *"
PythonCommandImportFromRandom = "from random import *"
PythonCommandImportFromTime = "from time import *"
PythonCommandImportFromTurtle = "from turtle import *"
@@ -66,6 +73,7 @@ PythonCommandImportCmath = "import cmath"
PythonCommandImportIon = "import ion"
PythonCommandImportKandinsky = "import kandinsky"
PythonCommandImportMath = "import math"
PythonCommandImportMatplotlibPyplot = "import matplotlib.pyplot"
PythonCommandImportRandom = "import random"
PythonCommandImportTime = "import time"
PythonCommandImportTurtle = "import turtle"
@@ -138,12 +146,15 @@ PythonCommandLog2 = "log2(x)"
PythonCommandLogComplex = "log(z,a)"
PythonCommandMathFunction = "math.function"
PythonCommandMathFunctionWithoutArg = "math.\x11"
PythonCommandMatplotlibPyplotFunction = "matplotlib.pyplot.function"
PythonCommandMatplotlibPyplotFunctionWithoutArg = "matplotlib.pyplot.\x11"
PythonCommandMax = "max(list)"
PythonCommandMin = "min(list)"
PythonCommandModf = "modf(x)"
PythonCommandMonotonic = "monotonic()"
PythonCommandOct = "oct(x)"
PythonCommandPhase = "phase(z)"
PythonCommandPlot = "plot(x,y)"
PythonCommandPolar = "polar(z)"
PythonCommandPop = "list.pop()"
PythonCommandPopWithoutArg = ".pop()"
@@ -165,8 +176,10 @@ PythonCommandRemoveWithoutArg = ".remove(\x11)"
PythonCommandReverse = "list.reverse()"
PythonCommandReverseWithoutArg = ".reverse()"
PythonCommandRound = "round(x, n)"
PythonCommandScatter = "scatter(x,y)"
PythonCommandSeed = "seed(x)"
PythonCommandSetPixel = "set_pixel(x,y,color)"
PythonCommandShow = "show()"
PythonCommandSin = "sin(x)"
PythonCommandSinComplex = "sin(z)"
PythonCommandSinh = "sinh(x)"
@@ -179,6 +192,7 @@ PythonCommandSqrtComplex = "sqrt(z)"
PythonCommandSum = "sum(list)"
PythonCommandTan = "tan(x)"
PythonCommandTanh = "tanh(x)"
PythonCommandText = "text(x,y,\"text\")"
PythonCommandTimeFunction = "time.function"
PythonCommandTimeFunctionWithoutArg = "time.\x11"
PythonCommandTrunc = "trunc(x)"

View File

@@ -34,9 +34,8 @@ ConsoleController::ConsoleController(Responder * parentResponder, App * pythonDe
m_selectableTableView(this, this, this, this),
m_editCell(this, pythonDelegate, this),
m_scriptStore(scriptStore),
m_sandboxController(this, this),
m_inputRunLoopActive(false),
m_preventEdition(false)
m_sandboxController(this),
m_inputRunLoopActive(false)
#if EPSILON_GETOPT
, m_locked(lockOnConsole)
#endif
@@ -82,14 +81,12 @@ void ConsoleController::runAndPrintForCommand(const char * command) {
assert(m_outputAccumulationBuffer[0] == '\0');
// Draw the console before running the code
m_preventEdition = true;
m_editCell.setText("");
m_editCell.setPrompt("");
refreshPrintOutput();
runCode(storedCommand);
m_preventEdition = false;
m_editCell.setPrompt(sStandardPromptText);
m_editCell.setEditing(true);
@@ -108,9 +105,7 @@ const char * ConsoleController::inputText(const char * prompt) {
m_inputRunLoopActive = true;
// Hide the sandbox if it is displayed
if (sandboxIsDisplayed()) {
hideSandbox();
}
hideAnyDisplayedViewController();
const char * promptText = prompt;
char * s = const_cast<char *>(prompt);
@@ -157,8 +152,7 @@ const char * ConsoleController::inputText(const char * prompt) {
m_editCell.clearAndReduceSize();
// Reload the history
m_selectableTableView.reloadData();
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
reloadData(true);
appsContainer->redrawWindow();
// Launch a new input loop
@@ -191,14 +185,21 @@ void ConsoleController::viewWillAppear() {
m_importScriptsWhenViewAppears = false;
autoImport();
}
m_selectableTableView.reloadData();
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
m_editCell.setEditing(true);
m_editCell.setText("");
reloadData(true);
}
void ConsoleController::didBecomeFirstResponder() {
Container::activeApp()->setFirstResponder(&m_editCell);
if (!isDisplayingViewController()) {
Container::activeApp()->setFirstResponder(&m_editCell);
} else {
/* A view controller might be displayed: for example, when pushing the
* console on the stack controller, we auto-import scripts during the
* 'viewWillAppear' and then we set the console as first responder. The
* sandbox or the matplotlib controller might have been pushed in the
* auto-import. */
Container::activeApp()->setFirstResponder(stackViewController()->topViewController());
}
}
bool ConsoleController::handleEvent(Ion::Events::Event event) {
@@ -347,11 +348,8 @@ bool ConsoleController::textFieldDidFinishEditing(TextField * textField, const c
}
telemetryReportEvent("Console", text);
runAndPrintForCommand(text);
if (!sandboxIsDisplayed()) {
m_selectableTableView.reloadData();
m_editCell.setEditing(true);
textField->setText("");
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
if (!isDisplayingViewController()) {
reloadData(true);
}
return true;
}
@@ -378,37 +376,53 @@ bool ConsoleController::textFieldDidAbortEditing(TextField * textField) {
return true;
}
void ConsoleController::displaySandbox() {
if (sandboxIsDisplayed()) {
return;
}
stackViewController()->push(&m_sandboxController);
}
void ConsoleController::hideSandbox() {
if (!sandboxIsDisplayed()) {
return;
}
m_sandboxController.hide();
}
void ConsoleController::resetSandbox() {
if (!sandboxIsDisplayed()) {
if (stackViewController()->topViewController() != sandbox()) {
return;
}
m_sandboxController.reset();
}
void ConsoleController::refreshPrintOutput() {
if (sandboxIsDisplayed()) {
void ConsoleController::displayViewController(ViewController * controller) {
if (stackViewController()->topViewController() == controller) {
return;
}
hideAnyDisplayedViewController();
stackViewController()->push(controller);
}
void ConsoleController::hideAnyDisplayedViewController() {
if (!isDisplayingViewController()) {
return;
}
stackViewController()->pop();
}
bool ConsoleController::isDisplayingViewController() {
/* The StackViewController model state is the best way to know wether the
* console is displaying a View Controller (Sandbox or Matplotlib). Indeed,
* keeping a boolean or a pointer raises the issue of when updating it - when
* 'viewWillAppear' or when 'didEnterResponderChain' - in both cases, the
* state would be wrong at some point... */
return stackViewController()->depth() > 2;
}
void ConsoleController::refreshPrintOutput() {
if (!isDisplayingViewController()) {
reloadData(false);
AppsContainer::sharedAppsContainer()->redrawWindow();
}
}
void ConsoleController::reloadData(bool isEditing) {
m_selectableTableView.reloadData();
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
if (m_preventEdition) {
if (isEditing) {
m_editCell.setEditing(true);
m_editCell.setText("");
} else {
m_editCell.setEditing(false);
}
AppsContainer::sharedAppsContainer()->redrawWindow();
}
/* printText is called by the Python machine.
@@ -457,12 +471,11 @@ void ConsoleController::printText(const char * text, size_t length) {
}
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();
}
/* 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. */
hideAnyDisplayedViewController();
if (script.importationStatus() || force) {
// Step 1 - Create the command "from scriptName import *".
@@ -488,11 +501,8 @@ void ConsoleController::autoImportScript(Script script, bool force) {
// Step 2 - Run the command
runAndPrintForCommand(command);
}
if (!sandboxIsDisplayed() && force) {
m_selectableTableView.reloadData();
m_selectableTableView.selectCellAtLocation(0, m_consoleStore.numberOfLines());
m_editCell.setEditing(true);
m_editCell.setText("");
if (!isDisplayingViewController() && force) {
reloadData(true);
}
}

View File

@@ -61,9 +61,10 @@ public:
bool textFieldDidAbortEditing(TextField * textField) override;
// MicroPython::ExecutionEnvironment
void displaySandbox() override;
void hideSandbox() override;
ViewController * sandbox() override { return &m_sandboxController; }
void resetSandbox() override;
void displayViewController(ViewController * controller) override;
void hideAnyDisplayedViewController() override;
void refreshPrintOutput() override;
void printText(const char * text, size_t length) override;
const char * inputText(const char * prompt) override;
@@ -82,6 +83,8 @@ private:
static constexpr int k_numberOfLineCells = (Ion::Display::Height - Metric::TitleBarHeight) / 14 + 2; // 14 = KDFont::SmallFont->glyphSize().height()
// k_numberOfLineCells = (240 - 18)/14 ~ 15.9. The 0.1 cell can be above and below the 15 other cells so we add +2 cells.
static constexpr int k_outputAccumulationBufferSize = 100;
bool isDisplayingViewController();
void reloadData(bool isEditing);
void flushOutputAccumulationBufferToStore();
void appendTextToOutputAccumulationBuffer(const char * text, size_t length);
void emptyOutputAccumulationBuffer();
@@ -103,7 +106,6 @@ private:
SandboxController m_sandboxController;
bool m_inputRunLoopActive;
bool m_autoImportScripts;
bool m_preventEdition;
#if EPSILON_GETOPT
bool m_locked;
#endif

View File

@@ -7,6 +7,8 @@
namespace Code {
static inline int minInt(int x, int y) { return x < y ? x : y; }
ConsoleEditCell::ConsoleEditCell(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, TextFieldDelegate * delegate) :
HighlightCell(),
Responder(parentResponder),
@@ -65,9 +67,12 @@ void ConsoleEditCell::clearAndReduceSize() {
const char * ConsoleEditCell::shiftCurrentTextAndClear() {
size_t previousBufferSize = m_textField.draftTextBufferSize();
m_textField.setDraftTextBufferSize(previousBufferSize + 1);
char * textFieldBuffer = m_textField.draftTextBuffer();
char * textFieldBuffer = const_cast<char *>(m_textField.text());
char * newTextPosition = textFieldBuffer + 1;
strlcpy(newTextPosition, textFieldBuffer, previousBufferSize);
assert(previousBufferSize > 0);
size_t copyLength = minInt(previousBufferSize - 1, strlen(textFieldBuffer));
memmove(newTextPosition, textFieldBuffer, copyLength);
newTextPosition[copyLength] = 0;
textFieldBuffer[0] = 0;
return newTextPosition;
}

View File

@@ -92,30 +92,6 @@ const ToolboxMessageTree MathModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLgamma, I18n::Message::PythonLgamma)
};
const ToolboxMessageTree KandinskyModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect)
};
const ToolboxMessageTree RandomModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandomFunction, I18n::Message::PythonRandomFunction, false, I18n::Message::PythonCommandRandomFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandrange, I18n::Message::PythonRandrange),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform)
};
const ToolboxMessageTree CMathModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromCmath, I18n::Message::PythonImportCmath, false),
@@ -132,6 +108,21 @@ const ToolboxMessageTree CMathModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinComplex, I18n::Message::PythonSin)
};
const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis, false, I18n::Message::PythonCommandAxisWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText)
};
const ToolboxMessageTree TurtleModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false),
@@ -167,6 +158,30 @@ const ToolboxMessageTree TurtleModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false)
};
const ToolboxMessageTree RandomModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandomFunction, I18n::Message::PythonRandomFunction, false, I18n::Message::PythonCommandRandomFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetrandbits, I18n::Message::PythonGetrandbits),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandrange, I18n::Message::PythonRandrange),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandint, I18n::Message::PythonRandint),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandChoice, I18n::Message::PythonChoice),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRandom, I18n::Message::PythonRandom, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform)
};
const ToolboxMessageTree KandinskyModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandKandinskyFunction, I18n::Message::PythonKandinskyFunction, false, I18n::Message::PythonCommandKandinskyFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGetPixel, I18n::Message::PythonGetPixel),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect)
};
const ToolboxMessageTree IonModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportIon, I18n::Message::PythonImportIon, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false),
@@ -231,8 +246,9 @@ const ToolboxMessageTree TimeModuleChildren[] = {
const ToolboxMessageTree modulesChildren[] = {
ToolboxMessageTree::Node(I18n::Message::MathModule, MathModuleChildren),
ToolboxMessageTree::Node(I18n::Message::CmathModule, CMathModuleChildren),
ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren),
ToolboxMessageTree::Node(I18n::Message::MatplotlibPyplotModule, MatplotlibPyplotModuleChildren),
ToolboxMessageTree::Node(I18n::Message::TurtleModule, TurtleModuleChildren),
ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren),
ToolboxMessageTree::Node(I18n::Message::KandinskyModule, KandinskyModuleChildren),
ToolboxMessageTree::Node(I18n::Message::IonModule, IonModuleChildren),
ToolboxMessageTree::Node(I18n::Message::TimeModule, TimeModuleChildren)
@@ -251,12 +267,15 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAbs, I18n::Message::PythonAbs),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcos, I18n::Message::PythonAcos),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAcosh, I18n::Message::PythonAcosh),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandArrow, I18n::Message::PythonArrow),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsin, I18n::Message::PythonAsin),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAsinh, I18n::Message::PythonAsinh),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan, I18n::Message::PythonAtan),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtan2, I18n::Message::PythonAtan2),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAtanh, I18n::Message::PythonAtanh),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandAxis, I18n::Message::PythonAxis, false, I18n::Message::PythonCommandAxisWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBackward, I18n::Message::PythonTurtleBackward),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBar, I18n::Message::PythonBar),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandBin, I18n::Message::PythonBin),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlack, I18n::Message::PythonTurtleBlack, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandBlue, I18n::Message::PythonTurtleBlue, false),
@@ -290,6 +309,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromIon, I18n::Message::PythonImportIon, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromKandinsky, I18n::Message::PythonImportKandinsky, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMath, I18n::Message::PythonImportMath, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromRandom, I18n::Message::PythonImportRandom, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTime, I18n::Message::PythonImportTime, false),
@@ -299,13 +319,16 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGoto, I18n::Message::PythonTurtleGoto),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGreen, I18n::Message::PythonTurtleGreen, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandGrey, I18n::Message::PythonTurtleGrey, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGrid, I18n::Message::PythonGrid),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHeading, I18n::Message::PythonTurtleHeading, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHex, I18n::Message::PythonHex),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandHideturtle, I18n::Message::PythonTurtleHideturtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandHist, I18n::Message::PythonHist),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportIon, I18n::Message::PythonImportIon, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMath, I18n::Message::PythonImportMath, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportMatplotlibPyplot, I18n::Message::PythonImportMatplotlibPyplot, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTime, I18n::Message::PythonImportTime, false),
@@ -335,6 +358,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog10, I18n::Message::PythonLog10),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLog2, I18n::Message::PythonLog2),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMathFunction, I18n::Message::PythonMathFunction, false, I18n::Message::PythonCommandMathFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMatplotlibPyplotFunction, I18n::Message::PythonMatplotlibPyplotFunction, false, I18n::Message::PythonCommandMatplotlibPyplotFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMax, I18n::Message::PythonMax),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandMin, I18n::Message::PythonMin),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandModf, I18n::Message::PythonModf),
@@ -350,6 +374,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPolar, I18n::Message::PythonPolar),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPosition, I18n::Message::PythonTurtlePosition, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPower, I18n::Message::PythonPower),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPlot, I18n::Message::PythonPlot),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPrint, I18n::Message::PythonPrint),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandPurple, I18n::Message::PythonTurtlePurple, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRadians, I18n::Message::PythonRadians),
@@ -364,9 +389,11 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandReset, I18n::Message::PythonTurtleReset, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandRight, I18n::Message::PythonTurtleRight),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandRound, I18n::Message::PythonRound),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScatter, I18n::Message::PythonScatter),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandSetheading, I18n::Message::PythonTurtleSetheading),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSetPixel, I18n::Message::PythonSetPixel),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSeed, I18n::Message::PythonSeed),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandShow, I18n::Message::PythonShow),
ToolboxMessageTree::Leaf(I18n::Message::PythonTurtleCommandShowturtle, I18n::Message::PythonTurtleShowturtle, false),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSin, I18n::Message::PythonSin),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSinh, I18n::Message::PythonSinh),
@@ -377,6 +404,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSum, I18n::Message::PythonSum),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTan, I18n::Message::PythonTan),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTanh, I18n::Message::PythonTanh),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandText, I18n::Message::PythonText),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTimeFunction, I18n::Message::PythonTimeFunction, false, I18n::Message::PythonCommandTimeFunctionWithoutArg),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTrunc, I18n::Message::PythonTrunc),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandTurtleFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandTurtleFunctionWithoutArg),

View File

@@ -1,14 +1,16 @@
#include "sandbox_controller.h"
#include <apps/apps_container.h>
extern "C" {
#include <python/port/mod/turtle/modturtle.h>
}
namespace Code {
SandboxController::SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment) :
SandboxController::SandboxController(Responder * parentResponder) :
ViewController(parentResponder),
m_solidColorView(Palette::CodeBackground),
m_executionEnvironment(executionEnvironment)
m_solidColorView(Palette::CodeBackground)
{
assert(executionEnvironment != nullptr);
}
StackViewController * SandboxController::stackViewController() {
@@ -20,19 +22,12 @@ void SandboxController::reset() {
redrawWindow();
}
void SandboxController::hide() {
stackViewController()->pop();
}
void SandboxController::viewWillAppear() {
assert(m_executionEnvironment != nullptr);
m_executionEnvironment->setSandboxIsDisplayed(true);
redrawWindow();
}
void SandboxController::viewDidDisappear() {
assert(m_executionEnvironment != nullptr);
m_executionEnvironment->setSandboxIsDisplayed(false);
modturtle_view_did_disappear();
}
bool SandboxController::handleEvent(Ion::Events::Event event) {

View File

@@ -11,10 +11,9 @@ namespace Code {
class SandboxController : public ViewController {
public:
SandboxController(Responder * parentResponder, MicroPython::ExecutionEnvironment * executionEnvironment);
SandboxController(Responder * parentResponder);
StackViewController * stackViewController();
void reset();
void hide();
// ViewController
View * view() override { return &m_solidColorView; }
@@ -26,7 +25,6 @@ public:
private:
void redrawWindow();
SolidColorView m_solidColorView;
MicroPython::ExecutionEnvironment * m_executionEnvironment;
};
}

View File

@@ -19,6 +19,7 @@ bool ScriptStore::ScriptNameIsFree(const char * baseName) {
ScriptStore::ScriptStore()
{
addScriptFromTemplate(ScriptTemplate::Squares());
addScriptFromTemplate(ScriptTemplate::Parabola());
addScriptFromTemplate(ScriptTemplate::Mandelbrot());
addScriptFromTemplate(ScriptTemplate::Polynomial());
}

View File

@@ -53,6 +53,37 @@ def roots(a,b,c):
else:
return None)");
constexpr ScriptTemplate parabolaScriptTemplate("parabola.py", "\x01" R"(from matplotlib.pyplot import *
from math import *
g=9.81
def x(t,v_0,alpha):
return v_0*cos(alpha)*t
def y(t,v_0,alpha,h_0):
return -0.5*g*t**2+v_0*sin(alpha)*t+h_0
def vx(v_0,alpha):
return v_0*cos(alpha)
def vy(t,v_0,alpha):
return -g*t+v_0*sin(alpha)
def t_max(v_0,alpha,h_0):
return (v_0*sin(alpha)+sqrt((v_0**2)*(sin(alpha)**2)+2*g*h_0))/g
def simulation(v_0=15,alpha=pi/4,h_0=2):
tMax=t_max(v_0,alpha,h_0)
accuracy=1/10**(floor(log10(tMax))-1)
T_MAX=floor(tMax*accuracy)+1
X=[x(t/accuracy,v_0,alpha) for t in range(T_MAX)]
Y=[y(t/accuracy,v_0,alpha,h_0) for t in range(T_MAX)]
VX=[vx(v_0,alpha) for t in range(T_MAX)]
VY=[vy(t/accuracy,v_0,alpha) for t in range(T_MAX)]
for i in range(T_MAX):
arrow(X[i],Y[i],VX[i]/accuracy,VY[i]/accuracy)
grid()
show())");
const ScriptTemplate * ScriptTemplate::Empty() {
return &emptyScriptTemplate;
}
@@ -69,4 +100,8 @@ const ScriptTemplate * ScriptTemplate::Polynomial() {
return &polynomialScriptTemplate;
}
const ScriptTemplate * ScriptTemplate::Parabola() {
return &parabolaScriptTemplate;
}
}

View File

@@ -10,6 +10,7 @@ public:
static const ScriptTemplate * Squares();
static const ScriptTemplate * Mandelbrot();
static const ScriptTemplate * Polynomial();
static const ScriptTemplate * Parabola();
const char * name() const { return m_name; }
const char * content() const { return m_value+1; }
const char * value() const { return m_value; }

View File

@@ -2,6 +2,7 @@ CmathModule = "cmath"
IonModule = "ion"
KandinskyModule = "kandinsky"
MathModule = "math"
MatplotlibPyplotModule = "matplotlib.pyplot"
TimeModule = "time"
TurtleModule = "turtle"
ForLoopMenu = "For"

View File

@@ -58,7 +58,7 @@ App::App(Snapshot * snapshot) :
m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey),
m_listHeader(&m_listStackViewController, &m_listFooter, &m_listController),
m_listStackViewController(&m_tabViewController, &m_listHeader),
m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader),
m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader),
m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController),
m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController),
m_graphStackViewController(&m_tabViewController, &m_graphHeader),

View File

@@ -30,7 +30,6 @@ protected:
MessageTextView m_defaultBannerView;
bool m_isActive;
private:
bool handleZoom(Ion::Events::Event event) override { return false; }
bool handleEnter() override;
bool moveCursorHorizontally(int direction, bool fast = false) override;
Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_graphRange; }

View File

@@ -11,8 +11,8 @@ static inline float maxFloat(float x, float y) { return x > y ? x : y; }
static inline double minDouble(double x, double y) { return x < y ? x : y; }
static inline double maxDouble(double x, double y) { return x > y ? x : y; }
GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion),
GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, curveViewRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, previousModelsVersions, rangeVersion, angleUnitVersion),
m_bannerView(this, inputEventHandlerDelegate, this),
m_view(curveViewRange, m_cursor, &m_bannerView, &m_cursorView),
m_graphRange(curveViewRange),

View File

@@ -15,7 +15,7 @@ namespace Graph {
class GraphController : public Shared::FunctionGraphController, public GraphControllerHelper {
public:
GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header);
GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, Shared::InteractiveCurveViewRange * curveViewRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header);
I18n::Message emptyMessage() override;
void viewWillAppear() override;
bool displayDerivativeInBanner() const { return m_displayDerivativeInBanner; }

View File

@@ -60,13 +60,12 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
}, f.operator->(), context(), f->color(), true, record == m_selectedRecord, m_highlightedStart, m_highlightedEnd);
/* Draw tangent */
if (m_tangent && record == m_selectedRecord) {
float tangentParameter[2];
tangentParameter[0] = f->approximateDerivative(m_curveViewCursor->x(), context());
tangentParameter[1] = -tangentParameter[0]*m_curveViewCursor->x()+f->evaluateXYAtParameter(m_curveViewCursor->x(), context()).x2();
drawCartesianCurve(ctx, rect, -INFINITY, INFINITY, [](float t, void * model, void * context) {
float * tangent = (float *)model;
return Poincare::Coordinate2D<float>(t, tangent[0]*t+tangent[1]);
}, tangentParameter, nullptr, Palette::GraphTangent);
float tangentParameterA = f->approximateDerivative(m_curveViewCursor->x(), context());
float tangentParameterB = -tangentParameterA*m_curveViewCursor->x()+f->evaluateXYAtParameter(m_curveViewCursor->x(), context()).x2();
// To represent the tangent, we draw segment from and to abscissas at the extremity of the drawn rect
float minAbscissa = pixelToFloat(Axis::Horizontal, rect.left());
float maxAbscissa = pixelToFloat(Axis::Horizontal, rect.right());
drawSegment(ctx, rect, minAbscissa, tangentParameterA*minAbscissa+tangentParameterB, maxAbscissa, tangentParameterA*maxAbscissa+tangentParameterB, Palette::GraphTangent, false);
}
continue;
}

View File

@@ -1,4 +1,4 @@
Apps = "Anwendungen"
AppsCapital = "OMEGA"
AppsCapital = "STAY HOME(GA)"
ForbidenAppInExamMode1 = "Diese Anwendung ist im"
ForbidenAppInExamMode2 = "Prüfungsmodus verboten"

View File

@@ -1,4 +1,4 @@
Apps = "Applications"
AppsCapital = "OMEGA"
AppsCapital = "STAY HOME(GA)"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -1,4 +1,4 @@
Apps = "Aplicaciones"
AppsCapital = "OMEGA"
AppsCapital = "STAY HOME(GA)"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -1,4 +1,4 @@
Apps = "Applications"
AppsCapital = "OMEGA"
AppsCapital = "STAY HOME(GA)"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -1,4 +1,4 @@
Apps = "Alkalmazások"
AppsCapital = "OMEGA"
AppsCapital = "STAY HOME(GA)"
ForbidenAppInExamMode1 = "Ez az alkalmazás"
ForbidenAppInExamMode2 = "tilos vizsga módban"

View File

@@ -1,4 +1,4 @@
Apps = "Aplicações"
AppsCapital = "OMEGA"
AppsCapital = "STAY HOME(GA)"
ForbidenAppInExamMode1 = "This application is"
ForbidenAppInExamMode2 = "forbidden in exam mode"

View File

@@ -25,9 +25,12 @@ double Distribution::rightIntegralFromAbscissa(double x) const {
}
double Distribution::finiteIntegralBetweenAbscissas(double a, double b) const {
if (b <= a) {
if (b < a) {
return 0.0;
}
if (a == b) {
return evaluateAtDiscreteAbscissa(a);
}
if (isContinuous()) {
return cumulativeDistributiveFunctionAtAbscissa(b) - cumulativeDistributiveFunctionAtAbscissa(a);
}
@@ -100,6 +103,7 @@ double Distribution::rightIntegralInverseForProbability(double * probability) {
}
double Distribution::evaluateAtDiscreteAbscissa(int k) const {
assert(isContinuous()); // Discrete distributions override this method
return 0.0;
}

View File

@@ -19,7 +19,13 @@ void assert_cumulative_distributive_function_direct_and_inverse_is(Probability::
quiz_assert(!std::isnan(r));
quiz_assert(!std::isinf(r));
quiz_assert(std::fabs(r-x) < FLT_EPSILON || std::fabs(r-x)/x < FLT_EPSILON);
}
void assert_finite_integral_between_abscissas_is(Probability::Distribution * distribution, double a, double b, double result) {
double r = distribution->finiteIntegralBetweenAbscissas(a, b);
quiz_assert(!std::isnan(r));
quiz_assert(!std::isinf(r));
quiz_assert(std::fabs(r-result) < FLT_EPSILON || std::fabs(r-result)/result < FLT_EPSILON);
}
//TODO other distributions
@@ -37,6 +43,13 @@ QUIZ_CASE(binomial_distribution) {
distribution.setParameterAtIndex(0.1, 1);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 0.0, 0.166771816996665822596668249389040283858776092529296875);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.0, 0.4817852491014791294077213024138472974300384521484375);
// B(21, 0.2)
distribution.setParameterAtIndex(21.0, 0);
distribution.setParameterAtIndex(0.2, 1);
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.21563235015849934848);
assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0);
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.398919847793223794688);
}
QUIZ_CASE(chi_squared_distribution) {
@@ -58,6 +71,12 @@ QUIZ_CASE(chi_squared_distribution) {
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.3, 0.047059684573231390369851823152202996425330638885498046875);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.9874567, 0.250530060451470470983537097708904184401035308837890625);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 4.987, 0.53051693435084168459781039928202517330646514892578125);
// Chi Squared distribution with 6 degrees of freedom
distribution.setParameterAtIndex(6.0, 0);
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.0);
assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0);
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.1328633002997339414718);
}
QUIZ_CASE(student_distribution) {
@@ -79,6 +98,12 @@ QUIZ_CASE(student_distribution) {
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, -4.987, 0.00167496657737900025118837898929768925881944596767425537109375);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.3, 0.876837383157582639370275501278229057788848876953125);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 2.9874567, 0.98612148076325445433809591122553683817386627197265625);
// Student distribution with 6 degrees of freedom
distribution.setParameterAtIndex(6.0, 0);
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 4.0, 0.0);
assert_finite_integral_between_abscissas_is(&distribution, 5.0, 4.0, 0.0);
assert_finite_integral_between_abscissas_is(&distribution, 4.0, 5.0, 0.002333318101494775250);
}
QUIZ_CASE(geometric_distribution) {
@@ -92,6 +117,12 @@ QUIZ_CASE(geometric_distribution) {
distribution.setParameterAtIndex(0.2, 0);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 7.0, 0.8322278399999998299563230830244719982147216796875);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 3.0, 0.5904);
// Geometric distribution with probability of success 0.4
distribution.setParameterAtIndex(0.4, 0);
assert_finite_integral_between_abscissas_is(&distribution, 1.0, 1.0, 0.24);
assert_finite_integral_between_abscissas_is(&distribution, 2.0, 1.0, 0.0);
assert_finite_integral_between_abscissas_is(&distribution, 1.0, 2.0, 0.384);
}
QUIZ_CASE(fisher_distribution) {
@@ -115,4 +146,10 @@ QUIZ_CASE(fisher_distribution) {
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.4, 0.94560850441205857);
assert_cumulative_distributive_function_direct_and_inverse_is(&distribution, 1.425, 0.95425004959692871775);
// Fisher distribution with d1 = 4 and d2 = 2
distribution.setParameterAtIndex(4.0, 0);
distribution.setParameterAtIndex(2.0, 1);
assert_finite_integral_between_abscissas_is(&distribution, 1.0, 1.0, 0.0);
assert_finite_integral_between_abscissas_is(&distribution, 2.0, 1.0, 0.0);
assert_finite_integral_between_abscissas_is(&distribution, 1.0, 2.0, 0.19555555555555555);
}

View File

@@ -38,7 +38,7 @@ App * App::Snapshot::unpack(Container * container) {
}
void App::Snapshot::reset() {
m_store.deleteAllPairs();
m_store.reset();
m_modelVersion = 0;
m_rangeVersion = 0;
setActiveTab(0);
@@ -59,7 +59,7 @@ App::App(Snapshot * snapshot, Poincare::Context * parentContext) :
m_calculationController(&m_calculationAlternateEmptyViewController, &m_calculationHeader, snapshot->store()),
m_calculationAlternateEmptyViewController(&m_calculationHeader, &m_calculationController, &m_calculationController),
m_calculationHeader(&m_tabViewController, &m_calculationAlternateEmptyViewController, &m_calculationController),
m_graphController(&m_graphAlternateEmptyViewController, this, &m_graphHeader, snapshot->store(), snapshot->cursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->graphSelectedDotIndex(), snapshot->selectedSeriesIndex()),
m_graphController(&m_graphAlternateEmptyViewController, this, &m_graphHeader, snapshot->store(), snapshot->cursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->graphSelectedDotIndex(), snapshot->selectedSeriesIndex()),
m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController),
m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController),
m_graphStackViewController(&m_tabViewController, &m_graphHeader),

View File

@@ -31,6 +31,7 @@ public:
int * graphSelectedDotIndex() { return &m_graphSelectedDotIndex; }
int * selectedSeriesIndex() { return &m_selectedSeriesIndex; }
uint32_t * modelVersion() { return &m_modelVersion; }
uint32_t * previousModelsVersions() { return m_store.seriesChecksum(); }
uint32_t * rangeVersion() { return &m_rangeVersion; }
private:
void tidy() override;

View File

@@ -168,6 +168,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
myCell->setFirstText(buffer);
buffer[0] = 'Y';
myCell->setSecondText(buffer);
assert(seriesNumber < Palette::numberOfDataColors());
myCell->setColor(Palette::DataColor[seriesNumber]);
return;
}

View File

@@ -14,8 +14,8 @@ static inline int maxInt(int x, int y) { return x > y ? x : y; }
namespace Regression {
GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex) :
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, store, &m_view, cursor, modelVersion, rangeVersion),
GraphController::GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex) :
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, store, &m_view, cursor, modelVersion, previousModelsVersions, rangeVersion),
m_crossCursorView(),
m_roundCursorView(),
m_bannerView(this, inputEventHandlerDelegate, this),
@@ -351,6 +351,11 @@ uint32_t GraphController::modelVersion() {
return m_store->storeChecksum();
}
uint32_t GraphController::modelVersionAtIndex(size_t i) {
assert(i < numberOfMemoizedVersions());
return *(m_store->seriesChecksum() + i);
}
uint32_t GraphController::rangeVersion() {
return m_store->rangeChecksum();
}
@@ -402,6 +407,7 @@ void GraphController::setRoundCrossCursorView() {
bool round = *m_selectedDotIndex < 0;
if (round) {
// Set the color although the cursor view stays round
assert(*m_selectedSeriesIndex < Palette::numberOfDataColors());
m_roundCursorView.setColor(Palette::DataColor[*m_selectedSeriesIndex]);
}
CursorView * nextCursorView = round ? static_cast<Shared::CursorView *>(&m_roundCursorView) : static_cast<Shared::CursorView *>(&m_crossCursorView);

View File

@@ -16,7 +16,7 @@ namespace Regression {
class GraphController : public Shared::InteractiveCurveViewController {
public:
GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex);
GraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, Store * store, Shared::CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, int * selectedDotIndex, int * selectedSeriesIndex);
ViewController * initialisationParameterController() override;
bool isEmpty() const override;
I18n::Message emptyMessage() override;
@@ -43,7 +43,9 @@ private:
// InteractiveCurveViewController
void initCursorParameters() override;
uint32_t modelVersion() override;
uint32_t modelVersionAtIndex(size_t i) override;
uint32_t rangeVersion() override;
size_t numberOfMemoizedVersions() const override { return Store::k_numberOfSeries; }
int selectedCurveIndex() const override { return *m_selectedSeriesIndex; }
bool closestCurveIndexIsSuitable(int newIndex, int currentIndex) const override;
Poincare::Coordinate2D<double> xyValues(int curveIndex, double x, Poincare::Context * context) const override;

View File

@@ -9,10 +9,8 @@ using namespace Shared;
namespace Regression {
GraphView::GraphView(Store * store, CurveViewCursor * cursor, BannerView * bannerView, Shared::CursorView * cursorView) :
CurveView(store, cursor, bannerView, cursorView),
m_store(store),
m_xLabels{},
m_yLabels{}
LabeledCurveView(store, cursor, bannerView, cursorView),
m_store(store)
{
}
@@ -24,6 +22,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
Poincare::Context * globContext = AppsContainer::sharedAppsContainer()->globalContext();
for (int series = 0; series < Store::k_numberOfSeries; series++) {
if (!m_store->seriesIsEmpty(series)) {
assert(series < Palette::numberOfDataColors());
KDColor color = Palette::DataColor[series];
Model * seriesModel = m_store->modelForSeries(series);
drawCartesianCurve(ctx, rect, -INFINITY, INFINITY, [](float abscissa, void * model, void * context) {
@@ -41,13 +40,4 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
}
}
char * GraphView::label(Axis axis, int index) const {
if (axis == Axis::Vertical) {
assert(index < k_maxNumberOfXLabels);
return (char *)m_yLabels[index];
}
assert(index < k_maxNumberOfYLabels);
return (char *)m_xLabels[index];
}
}

View File

@@ -3,19 +3,16 @@
#include "store.h"
#include "../constant.h"
#include "../shared/curve_view.h"
#include "../shared/labeled_curve_view.h"
namespace Regression {
class GraphView : public Shared::CurveView {
class GraphView : public Shared::LabeledCurveView {
public:
GraphView(Store * store, Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, Shared::CursorView * cursorView);
void drawRect(KDContext * ctx, KDRect rect) const override;
private:
char * label(Axis axis, int index) const override;
Store * m_store;
char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
};
}

View File

@@ -19,13 +19,14 @@ static_assert(Store::k_numberOfSeries == 3, "Number of series changed, Regressio
Store::Store() :
InteractiveCurveViewRange(),
DoublePairStore(),
m_seriesChecksum{0, 0, 0},
m_angleUnit(Poincare::Preferences::AngleUnit::Degree)
{
for (int i = 0; i < k_numberOfSeries; i++) {
m_regressionTypes[i] = Model::Type::Linear;
m_regressionChanged[i] = false;
}
resetMemoization();
}
void Store::reset() {
deleteAllPairs();
resetMemoization();
}
void Store::tidy() {
@@ -188,6 +189,13 @@ double Store::doubleCastedNumberOfPairsOfSeries(int series) const {
return DoublePairStore::numberOfPairsOfSeries(series);
}
void Store::resetMemoization() {
assert(((int)Model::Type::Linear) == 0);
memset(m_seriesChecksum, 0, sizeof(m_seriesChecksum));
memset(m_regressionTypes, 0, sizeof(m_regressionTypes));
memset(m_regressionChanged, 0, sizeof(m_regressionChanged));
}
float Store::maxValueOfColumn(int series, int i) const {
float maxColumn = -FLT_MAX;
for (int k = 0; k < numberOfPairsOfSeries(series); k++) {

View File

@@ -22,6 +22,7 @@ class Store : public Shared::InteractiveCurveViewRange, public Shared::DoublePai
public:
Store();
void reset();
// Clean pool
void tidy();
@@ -35,6 +36,7 @@ public:
assert((int)m_regressionTypes[series] >= 0 && (int)m_regressionTypes[series] < Model::k_numberOfModels);
return regressionModel((int)m_regressionTypes[series]);
}
uint32_t * seriesChecksum() { return m_seriesChecksum; }
// Dots
/* Return the closest dot to abscissa x above the regression curve if
@@ -70,6 +72,7 @@ public:
double squaredCorrelationCoefficient(int series) const;
private:
constexpr static float k_displayHorizontalMarginRatio = 0.05f;
void resetMemoization();
float maxValueOfColumn(int series, int i) const; //TODO LEA why float ?
float minValueOfColumn(int series, int i) const; //TODO LEA why float ?
Model * regressionModel(int index);

View File

@@ -55,7 +55,7 @@ App::App(Snapshot * snapshot) :
m_listFooter(&m_listHeader, &m_listController, &m_listController, ButtonRowController::Position::Bottom, ButtonRowController::Style::EmbossedGrey),
m_listHeader(nullptr, &m_listFooter, &m_listController),
m_listStackViewController(&m_tabViewController, &m_listHeader),
m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader),
m_graphController(&m_graphAlternateEmptyViewController, this, snapshot->functionStore(), snapshot->graphRange(), snapshot->cursor(), snapshot->indexFunctionSelectedByCursor(), snapshot->modelVersion(), snapshot->previousModelsVersions(), snapshot->rangeVersion(), snapshot->angleUnitVersion(), &m_graphHeader),
m_graphAlternateEmptyViewController(&m_graphHeader, &m_graphController, &m_graphController),
m_graphHeader(&m_graphStackViewController, &m_graphAlternateEmptyViewController, &m_graphController),
m_graphStackViewController(&m_tabViewController, &m_graphHeader),

View File

@@ -11,8 +11,8 @@ namespace Sequence {
static inline int minInt(int x, int y) { return (x < y ? x : y); }
static inline int maxInt(int x, int y) { return (x > y ? x : y); }
GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, rangeVersion, angleUnitVersion),
GraphController::GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header) :
FunctionGraphController(parentResponder, inputEventHandlerDelegate, header, graphRange, &m_view, cursor, indexFunctionSelectedByCursor, modelVersion, previousModelsVersions, rangeVersion, angleUnitVersion),
m_bannerView(this, inputEventHandlerDelegate, this),
m_view(sequenceStore, graphRange, m_cursor, &m_bannerView, &m_cursorView),
m_graphRange(graphRange),

View File

@@ -14,7 +14,7 @@ namespace Sequence {
class GraphController final : public Shared::FunctionGraphController {
public:
GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header);
GraphController(Responder * parentResponder, ::InputEventHandlerDelegate * inputEventHandlerDelegate, SequenceStore * sequenceStore, CurveViewRange * graphRange, Shared::CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion, ButtonRowController * header);
I18n::Message emptyMessage() override;
void viewWillAppear() override;
TermSumController * termSumController() { return &m_termSumController; }

View File

@@ -32,9 +32,9 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
if (x >= m_highlightedStart && x <= m_highlightedEnd && record == m_selectedRecord) {
KDColor color = m_shouldColorHighlighted ? s->color() : Palette::PrimaryText;
if (y >= 0.0f) {
drawSegment(ctx, rect, Axis::Vertical, x, 0.0f, y, color, 1);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, 0.0f, y, color, 1);
} else {
drawSegment(ctx, rect, Axis::Vertical, x, y, 0.0f, color, 1);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, y, 0.0f, color, 1);
}
}
}

View File

@@ -28,7 +28,6 @@ void Sequence::tidy() {
m_firstInitialCondition.tidyName();
m_secondInitialCondition.tidy();
m_secondInitialCondition.tidyName();
m_nameLayout = Layout();
}
Sequence::Type Sequence::type() const {
@@ -81,13 +80,10 @@ void Sequence::setInitialRank(int rank) {
}
Poincare::Layout Sequence::nameLayout() {
if (m_nameLayout.isUninitialized()) {
m_nameLayout = HorizontalLayout::Builder(
CodePointLayout::Builder(fullName()[0], KDFont::SmallFont),
VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Subscript)
);
}
return m_nameLayout;
return HorizontalLayout::Builder(
CodePointLayout::Builder(fullName()[0], KDFont::SmallFont),
VerticalOffsetLayout::Builder(CodePointLayout::Builder(symbol(), KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Subscript)
);
}
bool Sequence::isDefined() {

View File

@@ -24,8 +24,9 @@ public:
DoubleRecurrence = 2
};
Sequence(Ion::Storage::Record record = Record()) :
Function(record),
m_nameLayout() {}
Function(record)
{
}
I18n::Message parameterMessageName() const override;
CodePoint symbol() const override { return 'n'; }
void tidy() override;
@@ -111,7 +112,7 @@ private:
public:
SequenceModel() : Shared::ExpressionModel(), m_name() {}
void tidyName() { m_name = Poincare::Layout(); }
virtual Poincare::Layout name(Sequence * sequence);
Poincare::Layout name(Sequence * sequence);
protected:
virtual void buildName(Sequence * sequence) = 0;
Poincare::Layout m_name;
@@ -153,7 +154,6 @@ private:
DefinitionModel m_definition;
FirstInitialConditionModel m_firstInitialCondition;
SecondInitialConditionModel m_secondInitialCondition;
Poincare::Layout m_nameLayout;
};
}

View File

@@ -31,6 +31,7 @@ Ion::Storage::Record::ErrorStatus SequenceStore::addEmptyModel() {
const char * name = firstAvailableName(&nameIndex);
assert(name);
// Choose the corresponding color
assert(nameIndex < Palette::numberOfDataColors());
KDColor color = Palette::DataColor[nameIndex];
Sequence::RecordDataBuffer data(color);
// m_sequences

View File

@@ -1,6 +1,8 @@
app_shared_test_src = $(addprefix apps/shared/,\
continuous_function.cpp\
curve_view_range.cpp \
curve_view.cpp \
dots.cpp \
double_pair_store.cpp \
expression_model.cpp \
expression_model_handle.cpp \
@@ -9,8 +11,11 @@ app_shared_test_src = $(addprefix apps/shared/,\
global_context.cpp \
interactive_curve_view_range_delegate.cpp \
interactive_curve_view_range.cpp \
labeled_curve_view.cpp \
memoized_curve_view_range.cpp \
range_1D.cpp \
zoom_and_pan_curve_view_controller.cpp \
zoom_curve_view_controller.cpp \
)
app_shared_src = $(addprefix apps/shared/,\
@@ -18,9 +23,7 @@ app_shared_src = $(addprefix apps/shared/,\
buffer_function_title_cell.cpp \
buffer_text_view_with_text_field.cpp \
button_with_separator.cpp \
dots.cpp \
cursor_view.cpp \
curve_view.cpp \
curve_view_cursor.cpp \
editable_cell_table_view_controller.cpp \
expression_field_delegate_app.cpp \

View File

@@ -57,8 +57,7 @@ ContinuousFunction ContinuousFunction::NewModel(Ion::Storage::Record::ErrorStatu
static int s_colorIndex = 0;
// Create the record
char nameBuffer[SymbolAbstract::k_maxNameSize];
int numberOfColors = sizeof(Palette::DataColor)/sizeof(KDColor);
RecordDataBuffer data(Palette::DataColor[s_colorIndex++ % numberOfColors]);
RecordDataBuffer data(Palette::nextDataColor(&s_colorIndex));
if (baseName == nullptr) {
DefaultName(nameBuffer, SymbolAbstract::k_maxNameSize);
baseName = nameBuffer;

View File

@@ -1,11 +1,12 @@
#ifndef SHARED_CURSOR_VIEW_H
#define SHARED_CURSOR_VIEW_H
#include <escher.h>
#include <escher/transparent_view.h>
#include <escher/palette.h>
namespace Shared {
class CursorView : public View {
class CursorView : public TransparentView {
public:
virtual void setCursorFrame(KDRect frame, bool force) { View::setFrame(frame, force); }
void drawRect(KDContext * ctx, KDRect rect) const override;

View File

@@ -106,11 +106,11 @@ void CurveView::setOkView(View * okView) {
* m_frame.height() - 1 yMin()
*/
const float CurveView::pixelWidth() const {
float CurveView::pixelWidth() const {
return (m_curveViewRange->xMax() - m_curveViewRange->xMin()) / (m_frame.width() - 1);
}
const float CurveView::pixelHeight() const {
float CurveView::pixelHeight() const {
return (m_curveViewRange->yMax() - m_curveViewRange->yMin()) / (m_frame.height() - 1);
}
@@ -374,7 +374,7 @@ void CurveView::drawLabelsAndGraduations(KDContext * ctx, KDRect rect, Axis axis
position = positionLabel(horizontalCoordinate, labelPosition, textSize, RelativePosition::Before, RelativePosition::None);
if (floatingLabels == FloatingPosition::Min) {
position = KDPoint(k_labelMargin, position.y());
} else if (floatingLabels == FloatingPosition::Min) {
} else if (floatingLabels == FloatingPosition::Max) {
position = KDPoint(Ion::Display::Width - textSize.width() - k_labelMargin, position.y());
}
}
@@ -386,7 +386,7 @@ DrawLabel:
}
}
void CurveView::drawSegment(KDContext * ctx, KDRect rect, Axis axis, float coordinate, float lowerBound, float upperBound, KDColor color, KDCoordinate thickness, KDCoordinate dashSize) const {
void CurveView::drawHorizontalOrVerticalSegment(KDContext * ctx, KDRect rect, Axis axis, float coordinate, float lowerBound, float upperBound, KDColor color, KDCoordinate thickness, KDCoordinate dashSize) const {
KDCoordinate min = (axis == Axis::Horizontal) ? rect.x() : rect.y();
KDCoordinate max = (axis == Axis::Horizontal) ? rect.x() + rect.width() : rect.y() + rect.height();
KDCoordinate start = std::isinf(lowerBound) ? min : std::round(floatToPixel(axis, lowerBound));
@@ -417,6 +417,14 @@ void CurveView::drawSegment(KDContext * ctx, KDRect rect, Axis axis, float coord
}
}
void CurveView::drawSegment(KDContext * ctx, KDRect rect, float x, float y, float u, float v, KDColor color, bool thick) const {
float pxf = floatToPixel(Axis::Horizontal, x);
float pyf = floatToPixel(Axis::Vertical, y);
float puf = floatToPixel(Axis::Horizontal, u);
float pvf = floatToPixel(Axis::Vertical, v);
straightJoinDots(ctx, rect, pxf, pyf, puf, pvf, color, thick);
}
void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size) const {
KDCoordinate diameter = 0;
const uint8_t * mask = nullptr;
@@ -444,6 +452,47 @@ void CurveView::drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor
ctx->blendRectWithMask(dotRect, color, mask, workingBuffer);
}
void CurveView::drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowLength, float angle) const {
/* Let's call the following variables L and l:
*
* / |
* / |
* / l
* / |
* / |
* <--------------------------------------------------
* \
* \
* \
* \
* \
*
* ----- L -----
*
**/
assert(angle >= 0.0f);
/* We compute the arrow segments in pixels in order to correctly size the
* arrow without depending on the displayed range.
* Warning: the computed values are relative so we need to add/subtract the
* pixel position of 0s. */
float x0Pixel = floatToPixel(Axis::Horizontal, 0.0f);
float y0Pixel = floatToPixel(Axis::Vertical, 0.0f);
float dxPixel = floatToPixel(Axis::Horizontal, dx) - x0Pixel;
float dyPixel = y0Pixel - floatToPixel(Axis::Vertical, dy);
float dx2dy2 = std::sqrt(dxPixel*dxPixel+dyPixel*dyPixel);
float L = pixelArrowLength;
float l = angle*L;
float arrow1dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 + l*dyPixel/dx2dy2);
float arrow1dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 - l*dxPixel/dx2dy2));
drawSegment(ctx, rect, x, y, x - arrow1dx, y - arrow1dy, color, false);
float arrow2dx = pixelToFloat(Axis::Horizontal, x0Pixel + L*dxPixel/dx2dy2 - l*dyPixel/dx2dy2);
float arrow2dy = pixelToFloat(Axis::Vertical, y0Pixel - (L*dyPixel/dx2dy2 + l*dxPixel/dx2dy2));
drawSegment(ctx, rect, x, y, x - arrow2dx, y - arrow2dy, color, false);
}
void CurveView::drawGrid(KDContext * ctx, KDRect rect) const {
KDColor boldColor = Palette::GridPrimaryLine;
KDColor lightColor = Palette::GridSecondaryLine;
@@ -537,7 +586,7 @@ void CurveView::drawCurve(KDContext * ctx, KDRect rect, float tStart, float tEnd
x = xy.x1();
y = xy.x2();
if (colorUnderCurve && !std::isnan(x) && colorLowerBound < x && x < colorUpperBound && !(std::isnan(y) || std::isinf(y))) {
drawSegment(ctx, rect, Axis::Vertical, x, minFloat(0.0f, y), maxFloat(0.0f, y), color, 1);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, x, minFloat(0.0f, y), maxFloat(0.0f, y), color, 1);
}
joinDots(ctx, rect, xyEvaluation, model, context, drawStraightLinesEarly, previousT, previousX, previousY, t, x, y, color, thick, k_maxNumberOfIterations);
} while (true);

View File

@@ -38,8 +38,8 @@ public:
void setBannerView(View * bannerView);
void setOkView(View * okView);
void setForceOkDisplay(bool force) { m_forceOkDisplay = force; }
const float pixelWidth() const;
const float pixelHeight() const;
float pixelWidth() const;
float pixelHeight() const;
protected:
CurveViewRange * curveViewRange() const { return m_curveViewRange; }
void setCurveViewRange(CurveViewRange * curveViewRange);
@@ -59,18 +59,47 @@ protected:
float floatToPixel(Axis axis, float f) const;
void drawLine(KDContext * ctx, KDRect rect, Axis axis,
float coordinate, KDColor color, KDCoordinate thickness = 1, KDCoordinate dashSize = -1) const {
return drawSegment(ctx, rect, axis, coordinate, -INFINITY, INFINITY, color,
return drawHorizontalOrVerticalSegment(ctx, rect, axis, coordinate, -INFINITY, INFINITY, color,
thickness, dashSize);
}
void drawSegment(KDContext * ctx, KDRect rect, Axis axis,
void drawHorizontalOrVerticalSegment(KDContext * ctx, KDRect rect, Axis axis,
float coordinate, float lowerBound, float upperBound,
KDColor color, KDCoordinate thickness = 1, KDCoordinate dashSize = -1) const;
void drawSegment(KDContext * ctx, KDRect rect,
float x, float y, float u, float v,
KDColor color, bool thick = true
) const;
enum class Size : uint8_t {
Small,
Medium,
Large
};
void drawDot(KDContext * ctx, KDRect rect, float x, float y, KDColor color, Size size = Size::Small) const;
/* 'drawArrow' draws the edge of an arrow pointing to (x,y) with the
* orientation (dx,dy).
* The parameters defining the shape of the arrow are the length in pixel of
* the projection of the arrow on the segment -'pixelArrowLength'- and the
* tangent of the angle between the segment and each wing of the arrow called
* 'angle'.
*
* / |
* / |
* / L
* / |
* / |
* <--------------------------------------------------
* \
* \
* \
* \
* \
*
* <--- pl --->
*
* pl = pixelArrowLength
* tan(angle) = L/pl
*/
void drawArrow(KDContext * ctx, KDRect rect, float x, float y, float dx, float dy, KDColor color, KDCoordinate pixelArrowLength = 10, float angle = 0.4f) const;
void drawGrid(KDContext * ctx, KDRect rect) const;
void drawAxes(KDContext * ctx, KDRect rect) const;
void drawAxis(KDContext * ctx, KDRect rect, Axis axis) const;
@@ -100,7 +129,7 @@ private:
float min(Axis axis) const;
float max(Axis axis) const;
float gridUnit(Axis axis) const;
virtual char * label(Axis axis, int index) const = 0;
virtual char * label(Axis axis, int index) const { return nullptr; }
virtual size_t labelMaxGlyphLengthSize() const { return k_labelBufferMaxGlyphLength; }
int numberOfLabels(Axis axis) const;
/* Recursively join two dots (dichotomy). The method stops when the

View File

@@ -17,8 +17,8 @@ public:
virtual float xMax() const = 0;
virtual float yMin() const = 0;
virtual float yMax() const = 0;
const float xCenter() const { return (xMin() + xMax()) / 2; }
const float yCenter() const { return (yMin() + yMax()) / 2; }
float xCenter() const { return (xMin() + xMax()) / 2; }
float yCenter() const { return (yMin() + yMax()) / 2; }
virtual float xGridUnit() const {
return computeGridUnit(k_minNumberOfXGridUnits, k_maxNumberOfXGridUnits, xMax() - xMin());
}

View File

@@ -55,10 +55,12 @@ public:
// Colors
static KDColor colorOfSeriesAtIndex(int i) {
assert(i >= 0 && i < k_numberOfSeries);
assert(i < Palette::numberOfDataColors());
return Palette::DataColor[i];
}
static KDColor colorLightOfSeriesAtIndex(int i) {
assert(i >= 0 && i < k_numberOfSeries);
assert(i < Palette::numberOfLightDataColors());
return Palette::DataColorLight[i];
}
protected:

View File

@@ -11,11 +11,14 @@ FunctionApp::Snapshot::Snapshot() :
m_rangeVersion(0),
m_angleUnitVersion(Preferences::AngleUnit::Radian)
{
assert(m_previousModelsVersions[0] == 0);
}
void FunctionApp::Snapshot::reset() {
m_indexFunctionSelectedByCursor = 0;
m_modelVersion = 0;
assert(sizeof(m_previousModelsVersions) == sizeof(uint32_t) * FunctionGraphController::sNumberOfMemoizedModelVersions);
memset(m_previousModelsVersions, 0, sizeof(m_previousModelsVersions));
m_rangeVersion = 0;
setActiveTab(0);
}

View File

@@ -2,6 +2,7 @@
#define SHARED_FUNCTION_APP_H
#include "expression_field_delegate_app.h"
#include "function_graph_controller.h"
#include "function_store.h"
#include "curve_view_cursor.h"
#include "values_controller.h"
@@ -15,6 +16,7 @@ public:
Snapshot();
CurveViewCursor * cursor() { return &m_cursor; }
uint32_t * modelVersion() { return &m_modelVersion; }
uint32_t * previousModelsVersions() { return m_previousModelsVersions; }
uint32_t * rangeVersion() { return &m_rangeVersion; }
Poincare::Preferences::AngleUnit * angleUnitVersion() { return &m_angleUnitVersion; }
virtual FunctionStore * functionStore() = 0;
@@ -26,6 +28,7 @@ public:
private:
int m_indexFunctionSelectedByCursor;
uint32_t m_modelVersion;
uint32_t m_previousModelsVersions[FunctionGraphController::sNumberOfMemoizedModelVersions];
uint32_t m_rangeVersion;
Poincare::Preferences::AngleUnit m_angleUnitVersion;
};

View File

@@ -15,8 +15,8 @@ static inline float maxFloat(float x, float y) { return x > y ? x : y; }
static inline double minDouble(double x, double y) { return x < y ? x : y; }
static inline double maxDouble(double x, double y) { return x > y ? x : y; }
FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) :
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, rangeVersion),
FunctionGraphController::FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Preferences::AngleUnit * angleUnitVersion) :
InteractiveCurveViewController(parentResponder, inputEventHandlerDelegate, header, interactiveRange, curveView, cursor, modelVersion, previousModelsVersions, rangeVersion),
m_initialisationParameterController(this, interactiveRange),
m_angleUnitVersion(angleUnitVersion),
m_indexFunctionSelectedByCursor(indexFunctionSelectedByCursor)
@@ -183,6 +183,10 @@ uint32_t FunctionGraphController::modelVersion() {
return functionStore()->storeChecksum();
}
uint32_t FunctionGraphController::modelVersionAtIndex(size_t i) {
return functionStore()->storeChecksumAtIndex(i);
}
uint32_t FunctionGraphController::rangeVersion() {
return interactiveCurveViewRange()->rangeChecksum();
}

View File

@@ -13,7 +13,8 @@ namespace Shared {
class FunctionGraphController : public InteractiveCurveViewController, public FunctionBannerDelegate {
public:
FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion);
static constexpr size_t sNumberOfMemoizedModelVersions = 5;
FunctionGraphController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, int * indexFunctionSelectedByCursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion, Poincare::Preferences::AngleUnit * angleUnitVersion);
bool isEmpty() const override;
ViewController * initialisationParameterController() override;
void didBecomeFirstResponder() override;
@@ -49,7 +50,9 @@ private:
// InteractiveCurveViewController
bool moveCursorVertically(int direction) override;
uint32_t modelVersion() override;
uint32_t modelVersionAtIndex(size_t i) override;
uint32_t rangeVersion() override;
size_t numberOfMemoizedVersions() const override { return sNumberOfMemoizedModelVersions; }
InitialisationParameterController m_initialisationParameterController;
Poincare::Preferences::AngleUnit * m_angleUnitVersion;

View File

@@ -8,13 +8,11 @@ namespace Shared {
FunctionGraphView::FunctionGraphView(InteractiveCurveViewRange * graphRange,
CurveViewCursor * cursor, BannerView * bannerView, CursorView * cursorView) :
CurveView(graphRange, cursor, bannerView, cursorView),
LabeledCurveView(graphRange, cursor, bannerView, cursorView),
m_selectedRecord(),
m_highlightedStart(NAN),
m_highlightedEnd(NAN),
m_shouldColorHighlighted(false),
m_xLabels{},
m_yLabels{},
m_context(nullptr)
{
}
@@ -67,10 +65,6 @@ void FunctionGraphView::setAreaHighlightColor(bool highlightColor) {
}
}
char * FunctionGraphView::label(Axis axis, int index) const {
return (axis == Axis::Horizontal ? (char *)m_xLabels[index] : (char *)m_yLabels[index]);
}
void FunctionGraphView::reloadBetweenBounds(float start, float end) {
if (start == end) {
return;

View File

@@ -2,14 +2,14 @@
#define SHARED_FUNCTION_GRAPH_VIEW_H
#include <escher.h>
#include "curve_view.h"
#include "labeled_curve_view.h"
#include "function.h"
#include "../constant.h"
#include "interactive_curve_view_range.h"
namespace Shared {
class FunctionGraphView : public CurveView {
class FunctionGraphView : public LabeledCurveView {
public:
FunctionGraphView(InteractiveCurveViewRange * graphRange, CurveViewCursor * cursor,
BannerView * bannerView, CursorView * cursorView);
@@ -26,9 +26,6 @@ protected:
float m_highlightedEnd;
bool m_shouldColorHighlighted;
private:
char * label(Axis axis, int index) const override;
char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
Poincare::Context * m_context;
};

View File

@@ -6,4 +6,11 @@ uint32_t FunctionStore::storeChecksum() {
return Ion::Storage::sharedStorage()->checksum();
}
uint32_t FunctionStore::storeChecksumAtIndex(size_t i) {
if (numberOfActiveFunctions() <= i) {
return 0;
}
return activeRecordAtIndex(i).checksum();
}
}

View File

@@ -13,6 +13,7 @@ class FunctionStore : public ExpressionModelStore {
public:
FunctionStore() : ExpressionModelStore() {}
uint32_t storeChecksum();
uint32_t storeChecksumAtIndex(size_t i);
int numberOfActiveFunctions() const {
return numberOfModelsSatisfyingTest(&isFunctionActive, nullptr);
}

View File

@@ -7,10 +7,11 @@ using namespace Poincare;
namespace Shared {
InteractiveCurveViewController::InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion) :
InteractiveCurveViewController::InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion) :
SimpleInteractiveCurveViewController(parentResponder, cursor),
ButtonRowDelegate(header, nullptr),
m_modelVersion(modelVersion),
m_previousModelsVersions(previousModelsVersions),
m_rangeVersion(rangeVersion),
m_rangeParameterController(this, inputEventHandlerDelegate, interactiveRange),
m_zoomParameterController(this, interactiveRange, curveView),
@@ -132,11 +133,43 @@ Responder * InteractiveCurveViewController::defaultController() {
return tabController();
}
bool InteractiveCurveViewController::previousModelsWereAllDeleted() {
bool result = true;
const int modelsCount = numberOfCurves();
const int memoizationCount = numberOfMemoizedVersions();
// Look for a current model that is the same as in the previous version
for (int i = 0; i < modelsCount; i++) {
uint32_t currentVersion = modelVersionAtIndex(i);
for (int j = 0; j < memoizationCount; j++) {
uint32_t * previousVersion = m_previousModelsVersions + j;
if (currentVersion == *previousVersion) {
result = false;
break;
}
}
if (!result) {
break;
}
}
// Update the memoization
for (int i = 0; i < memoizationCount; i++) {
uint32_t * previousVersion = m_previousModelsVersions + i;
uint32_t newVersion = modelVersionAtIndex(i);
if (*previousVersion != newVersion) {
*previousVersion = newVersion;
}
}
return result;
}
void InteractiveCurveViewController::viewWillAppear() {
SimpleInteractiveCurveViewController::viewWillAppear();
uint32_t newModelVersion = modelVersion();
if (*m_modelVersion != newModelVersion) {
if (*m_modelVersion == 0 || numberOfCurves() == 1 || shouldSetDefaultOnModelChange()) {
// Put previousModelsWereAllDeleted first to update the model versions
if (previousModelsWereAllDeleted() || *m_modelVersion == 0 || numberOfCurves() == 1 || shouldSetDefaultOnModelChange()) {
interactiveCurveViewRange()->setDefault();
}
*m_modelVersion = newModelVersion;

View File

@@ -12,7 +12,7 @@ namespace Shared {
class InteractiveCurveViewController : public SimpleInteractiveCurveViewController, public InteractiveCurveViewRangeDelegate, public ButtonRowDelegate, public AlternateEmptyViewDefaultDelegate {
public:
InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * rangeVersion);
InteractiveCurveViewController(Responder * parentResponder, InputEventHandlerDelegate * inputEventHandlerDelegate, ButtonRowController * header, InteractiveCurveViewRange * interactiveRange, CurveView * curveView, CurveViewCursor * cursor, uint32_t * modelVersion, uint32_t * previousModelsVersions, uint32_t * rangeVersion);
const char * title() override;
bool handleEvent(Ion::Events::Event event) override;
@@ -28,6 +28,8 @@ public:
Responder * defaultController() override;
bool previousModelsWereAllDeleted();
void viewWillAppear() override;
void viewDidDisappear() override;
void willExitResponderChain(Responder * nextFirstResponder) override;
@@ -39,6 +41,7 @@ protected:
virtual void initCursorParameters() = 0;
virtual bool moveCursorVertically(int direction) = 0;
virtual uint32_t modelVersion() = 0;
virtual uint32_t modelVersionAtIndex(size_t i) = 0;
virtual uint32_t rangeVersion() = 0;
bool isCursorVisible();
@@ -66,7 +69,9 @@ private:
float addMargin(float x, float range, bool isVertical, bool isMin) override;
virtual bool shouldSetDefaultOnModelChange() const { return false; }
virtual size_t numberOfMemoizedVersions() const = 0;
uint32_t * m_modelVersion;
uint32_t * m_previousModelsVersions;
uint32_t * m_rangeVersion;
RangeParameterController m_rangeParameterController;
ZoomParameterController m_zoomParameterController;

View File

@@ -0,0 +1,31 @@
#include "labeled_curve_view.h"
namespace Shared {
char * HorizontallyLabeledCurveView::label(Axis axis, int index) const {
if (axis == Axis::Horizontal) {
assert(index < k_maxNumberOfXLabels);
return m_xLabels[index];
}
return nullptr;
}
char * VerticallyLabeledCurveView::label(Axis axis, int index) const {
if (axis == Axis::Vertical) {
assert(index < k_maxNumberOfYLabels);
return m_yLabels[index];
}
return nullptr;
}
char * LabeledCurveView::label(Axis axis, int index) const {
if (axis == Axis::Horizontal) {
assert(index < k_maxNumberOfXLabels);
return m_xLabels[index];
} else {
assert(index < k_maxNumberOfYLabels);
return m_yLabels[index];
}
}
}

View File

@@ -0,0 +1,37 @@
#ifndef SHARED_LABELED_CURVE_VIEW_H
#define SHARED_LABELED_CURVE_VIEW_H
#include "curve_view.h"
/* This CurveView subclass provides label storage for common use cases */
namespace Shared {
class HorizontallyLabeledCurveView : public CurveView {
public:
using CurveView::CurveView;
private:
char * label(Axis axis, int index) const override;
mutable char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
};
class VerticallyLabeledCurveView : public CurveView {
public:
using CurveView::CurveView;
private:
char * label(Axis axis, int index) const override;
mutable char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
};
class LabeledCurveView : public CurveView {
public:
using CurveView::CurveView;
private:
char * label(Axis axis, int index) const override;
mutable char m_xLabels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
mutable char m_yLabels[k_maxNumberOfYLabels][k_labelBufferMaxSize];
};
}
#endif

View File

@@ -49,6 +49,14 @@ void RoundCursorView::setCursorFrame(KDRect f, bool force) {
CursorView::setCursorFrame(f, force);
}
void RoundCursorView::markRectAsDirty(KDRect rect) {
/* The CursorView class inherits from TransparentView, so does
* RoundCursorView. The method markRectAsDirty is thus overriden to avoid
* marking as dirty the background of the RoundCursorView in its superview.
*/
View::markRectAsDirty(rect);
}
#ifdef GRAPH_CURSOR_SPEEDUP
bool RoundCursorView::eraseCursorIfPossible() {
if (!m_underneathPixelBufferLoaded) {

View File

@@ -24,6 +24,7 @@ public:
void resetMemoization() const { m_underneathPixelBufferLoaded = false; }
#endif
private:
void markRectAsDirty(KDRect rect) override;
#ifdef GRAPH_CURSOR_SPEEDUP
bool eraseCursorIfPossible();
#endif

View File

@@ -6,16 +6,6 @@ using namespace Poincare;
namespace Shared {
SimpleInteractiveCurveViewController::SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor) :
ViewController(parentResponder),
m_cursor(cursor)
{
}
View * SimpleInteractiveCurveViewController::view() {
return curveView();
}
bool SimpleInteractiveCurveViewController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::Plus || event == Ion::Events::Minus) {
return handleZoom(event);
@@ -36,13 +26,6 @@ bool SimpleInteractiveCurveViewController::textFieldDidReceiveEvent(TextField *
return TextFieldDelegate::textFieldDidReceiveEvent(textField, event);
}
bool SimpleInteractiveCurveViewController::handleZoom(Ion::Events::Event event) {
float ratio = event == Ion::Events::Plus ? 2.0f/3.0f : 3.0f/2.0f;
interactiveCurveViewRange()->zoom(ratio, m_cursor->x(), m_cursor->y());
curveView()->reload();
return true;
}
bool SimpleInteractiveCurveViewController::handleLeftRightEvent(Ion::Events::Event event) {
int direction = event == Ion::Events::Left ? -1 : 1;
if (moveCursorHorizontally(direction, Ion::Events::isLongRepetition())) {

View File

@@ -1,21 +1,17 @@
#ifndef SHARED_SIMPLE_INTERACTIVE_CURVE_VIEW_CONTROLLER_H
#define SHARED_SIMPLE_INTERACTIVE_CURVE_VIEW_CONTROLLER_H
#include <escher/view_controller.h>
#include "text_field_delegate.h"
#include "interactive_curve_view_range.h"
#include "curve_view_cursor.h"
#include "curve_view.h"
#include "zoom_curve_view_controller.h"
namespace Shared {
/* SimpleInteractiveCurveViewController is a View controller with a cursor that
* can handles zoom in/out and left and right events. */
class SimpleInteractiveCurveViewController : public ViewController, public TextFieldDelegate {
class SimpleInteractiveCurveViewController : public ZoomCurveViewController, public TextFieldDelegate {
public:
SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor);
View * view() override;
SimpleInteractiveCurveViewController(Responder * parentResponder, CurveViewCursor * cursor) : ZoomCurveViewController(parentResponder), m_cursor(cursor) {}
bool handleEvent(Ion::Events::Event event) override;
bool textFieldDidReceiveEvent(TextField * textField, Ion::Events::Event event) override;
protected:
@@ -24,15 +20,15 @@ protected:
virtual float cursorTopMarginRatio() { return 0.07f; } // (cursorHeight/2)/(graphViewHeight-1)
virtual float cursorBottomMarginRatio() = 0; // (cursorHeight/2+bannerHeight)/(graphViewHeight-1)
constexpr static float k_numberOfCursorStepsInGradUnit = 5.0f;
virtual bool handleZoom(Ion::Events::Event event);
// ZoomCurveViewController
float xFocus() override { return m_cursor->x(); }
float yFocus() override { return m_cursor->y(); }
virtual bool handleLeftRightEvent(Ion::Events::Event event);
virtual void reloadBannerView() = 0;
/* the result of moveCursorVertically/Horizontally means:
* false -> the cursor cannot move in this direction
* true -> the cursor moved */
virtual bool moveCursorHorizontally(int direction, bool fast = false) { return false; }
virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0;
virtual CurveView * curveView() = 0;
virtual bool handleEnter() = 0;
CurveViewCursor * m_cursor;
};

View File

@@ -3,7 +3,6 @@
#include <poincare/empty_layout.h>
#include <poincare/condensed_sum_layout.h>
#include <poincare/layout_helper.h>
#include <poincare/preferences.h>
#include "poincare_helpers.h"
#include <assert.h>
@@ -150,14 +149,13 @@ void SumGraphController::reloadBannerView() {
m_legendView.setEditableZone(m_cursor->x());
result = NAN;
}
m_legendView.setSumSymbol(m_step, m_startSum, endSum, result, functionLayout);
m_legendView.setSumLayout(m_step, m_startSum, endSum, result, functionLayout);
}
/* Legend View */
SumGraphController::LegendView::LegendView(SumGraphController * controller, InputEventHandlerDelegate * inputEventHandlerDelegate, CodePoint sumSymbol) :
m_sum(0.0f, 0.5f, Palette::PrimaryText, Palette::SubMenuBackground),
m_sumLayout(),
m_legend(k_font, I18n::Message::Default, 0.0f, 0.5f, Palette::PrimaryText, Palette::SubMenuBackground),
m_editableZone(controller, m_textBuffer, k_editableZoneBufferSize, TextField::maxBufferSize(), inputEventHandlerDelegate, controller, k_font, 0.0f, 0.5f, Palette::PrimaryText, Palette::SubMenuBackground),
m_sumSymbol(sumSymbol)
@@ -179,54 +177,41 @@ void SumGraphController::LegendView::setLegendMessage(I18n::Message message, Ste
}
void SumGraphController::LegendView::setEditableZone(double d) {
constexpr int precision = Preferences::MediumNumberOfSignificantDigits;
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
char buffer[bufferSize];
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(d, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
char buffer[k_valuesBufferSize];
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(d, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal);
m_editableZone.setText(buffer);
}
void SumGraphController::LegendView::setSumSymbol(Step step, double start, double end, double result, Layout functionLayout) {
void SumGraphController::LegendView::setSumLayout(Step step, double start, double end, double result, Layout functionLayout) {
assert(step == Step::Result || functionLayout.isUninitialized());
constexpr int sigmaLength = 2;
const CodePoint sigma[sigmaLength] = {' ', m_sumSymbol};
if (step == Step::FirstParameter) {
m_sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength);
} else if (step == Step::SecondParameter) {
constexpr int precision = Preferences::MediumNumberOfSignificantDigits;
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(precision);
char buffer[bufferSize];
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
m_sumLayout = CondensedSumLayout::Builder(
LayoutHelper::CodePointString(sigma, sigmaLength),
Poincare::Layout sumLayout = LayoutHelper::CodePointString(sigma, sigmaLength);
if (step != Step::FirstParameter) {
char buffer[k_valuesBufferSize];
Layout endLayout;
if (step == Step::SecondParameter) {
endLayout = EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false);
} else {
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(end, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal);
endLayout = LayoutHelper::String(buffer, strlen(buffer), k_font);
}
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(start, buffer, k_valuesBufferSize, k_valuesPrecision, Preferences::PrintFloatMode::Decimal);
sumLayout = CondensedSumLayout::Builder(
sumLayout,
LayoutHelper::String(buffer, strlen(buffer), k_font),
EmptyLayout::Builder(EmptyLayoutNode::Color::Yellow, false, k_font, false));
} else {
constexpr int precision = Preferences::LargeNumberOfSignificantDigits;
constexpr int sizeForPrecision = PrintFloat::charSizeForFloatsWithPrecision(precision);
constexpr int bufferSize = 2 + sizeForPrecision;
char buffer[bufferSize];
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(start, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
Layout start = LayoutHelper::String(buffer, strlen(buffer), k_font);
PoincareHelpers::ConvertFloatToTextWithDisplayMode<double>(end, buffer, bufferSize, precision, Preferences::PrintFloatMode::Decimal);
Layout end = LayoutHelper::String(buffer, strlen(buffer), k_font);
m_sumLayout = CondensedSumLayout::Builder(
LayoutHelper::CodePointString(sigma, sigmaLength),
start,
end);
strlcpy(buffer, "= ", 3);
PoincareHelpers::ConvertFloatToText<double>(result, buffer+2, bufferSize-2, precision);
m_sumLayout = HorizontalLayout::Builder(
m_sumLayout,
functionLayout,
LayoutHelper::String(buffer, strlen(buffer), k_font));
}
m_sum.setLayout(m_sumLayout);
if (step == Step::Result) {
m_sum.setAlignment(0.5f, 0.5f);
} else {
m_sum.setAlignment(0.0f, 0.5f);
endLayout);
if (step == Step::Result) {
PoincareHelpers::ConvertFloatToText<double>(result, buffer, k_valuesBufferSize, k_valuesPrecision);
sumLayout = HorizontalLayout::Builder(
sumLayout,
functionLayout,
LayoutHelper::String("= ", 2, k_font),
LayoutHelper::String(buffer, strlen(buffer), k_font));
}
}
m_sum.setLayout(sumLayout);
m_sum.setAlignment(0.5f * (step == Step::Result), 0.5f);
layoutSubviews(step, false);
}

View File

@@ -55,9 +55,11 @@ private:
void drawRect(KDContext * ctx, KDRect rect) const override;
void setLegendMessage(I18n::Message message, Step step);
void setEditableZone(double d);
void setSumSymbol(Step step, double start, double end, double result, Poincare::Layout functionLayout);
void setSumLayout(Step step, double start, double end, double result, Poincare::Layout functionLayout);
private:
constexpr static KDCoordinate k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize;
constexpr static size_t k_editableZoneBufferSize = Poincare::PrintFloat::k_maxFloatCharSize;
constexpr static int k_valuesPrecision = Poincare::Preferences::MediumNumberOfSignificantDigits;
constexpr static int k_valuesBufferSize = Poincare::PrintFloat::charSizeForFloatsWithPrecision(k_valuesPrecision);
constexpr static KDCoordinate k_legendHeight = 35;
constexpr static const KDFont * k_font = KDFont::SmallFont;
static KDCoordinate editableZoneWidth() { return 12*k_font->glyphSize().width(); }
@@ -69,7 +71,6 @@ private:
void layoutSubviews(bool force = false) override;
void layoutSubviews(Step step, bool force);
ExpressionView m_sum;
Poincare::Layout m_sumLayout;
MessageTextView m_legend;
TextField m_editableZone;
char m_textBuffer[k_editableZoneBufferSize];

View File

@@ -0,0 +1,35 @@
#include "zoom_and_pan_curve_view_controller.h"
#include <cmath>
#include <assert.h>
using namespace Poincare;
namespace Shared {
bool ZoomAndPanCurveViewController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::Left || event == Ion::Events::Right || event == Ion::Events::Up || event == Ion::Events::Down) {
return handlePan(event);
}
return ZoomCurveViewController::handleEvent(event);
}
bool ZoomAndPanCurveViewController::handlePan(Ion::Events::Event event) {
float xMove = 0.0f;
float yMove = 0.0f;
if (event == Ion::Events::Up) {
yMove = interactiveCurveViewRange()->yGridUnit();
} else if (event == Ion::Events::Down) {
yMove = -interactiveCurveViewRange()->yGridUnit();
} else if (event == Ion::Events::Left) {
xMove = -interactiveCurveViewRange()->xGridUnit();
} else {
assert(event == Ion::Events::Right);
xMove = interactiveCurveViewRange()->xGridUnit();
}
interactiveCurveViewRange()->panWithVector(xMove, yMove);
curveView()->reload();
return true;
}
}

View File

@@ -0,0 +1,23 @@
#ifndef SHARED_ZOOM_AND_PAN_CURVE_VIEW_CONTROLLER_H
#define SHARED_ZOOM_AND_PAN_CURVE_VIEW_CONTROLLER_H
#include "zoom_curve_view_controller.h"
namespace Shared {
/* ZoomAndPanCurveViewController is a View controller with a cursor that can
* handles zoom in/out and directional pan events. */
class ZoomAndPanCurveViewController : public ZoomCurveViewController {
public:
ZoomAndPanCurveViewController(Responder * parentResponder) : ZoomCurveViewController(parentResponder) {}
bool handleEvent(Ion::Events::Event event) override;
protected:
virtual bool handlePan(Ion::Events::Event event);
float xFocus() override { return interactiveCurveViewRange()->xCenter(); }
float yFocus() override { return interactiveCurveViewRange()->yCenter(); }
};
}
#endif

View File

@@ -0,0 +1,23 @@
#include "zoom_curve_view_controller.h"
#include <cmath>
#include <assert.h>
using namespace Poincare;
namespace Shared {
bool ZoomCurveViewController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::Plus || event == Ion::Events::Minus) {
return handleZoom(event);
}
return false;
}
bool ZoomCurveViewController::handleZoom(Ion::Events::Event event) {
float ratio = event == Ion::Events::Plus ? 2.0f/3.0f : 3.0f/2.0f;
interactiveCurveViewRange()->zoom(ratio, xFocus(), yFocus());
curveView()->reload();
return true;
}
}

View File

@@ -0,0 +1,30 @@
#ifndef SHARED_ZOOM_CURVE_VIEW_CONTROLLER_H
#define SHARED_ZOOM_CURVE_VIEW_CONTROLLER_H
#include <escher/view_controller.h>
#include "interactive_curve_view_range.h"
#include "curve_view_cursor.h"
#include "curve_view.h"
namespace Shared {
/* ZoomCurveViewController is a View controller with a cursor that can handles
* zoom in/out events. */
class ZoomCurveViewController : public ViewController {
public:
ZoomCurveViewController(Responder * parentResponder) : ViewController(parentResponder) {}
View * view() override { return curveView(); }
bool handleEvent(Ion::Events::Event event) override;
protected:
virtual bool handleZoom(Ion::Events::Event event);
virtual InteractiveCurveViewRange * interactiveCurveViewRange() = 0;
virtual CurveView * curveView() = 0;
virtual float xFocus() = 0;
virtual float yFocus() = 0;
CurveViewCursor * m_cursor;
};
}
#endif

View File

@@ -5,7 +5,7 @@
namespace Shared {
ZoomParameterController::ZoomParameterController(Responder * parentResponder, InteractiveCurveViewRange * interactiveRange, CurveView * curveView) :
ViewController(parentResponder),
ZoomAndPanCurveViewController(parentResponder),
m_contentView(curveView),
m_interactiveRange(interactiveRange)
{
@@ -15,45 +15,6 @@ const char * ZoomParameterController::title() {
return I18n::translate(I18n::Message::Zoom);
}
View * ZoomParameterController::view() {
return &m_contentView;
}
bool ZoomParameterController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::Plus) {
m_interactiveRange->zoom(2.0f/3.0f, m_interactiveRange->xCenter(), m_interactiveRange->yCenter());
m_contentView.curveView()->reload();
return true;
}
if (event == Ion::Events::Minus) {
m_interactiveRange->zoom(3.0f/2.0f, m_interactiveRange->xCenter(), m_interactiveRange->yCenter());
m_contentView.curveView()->reload();
return true;
}
if (event == Ion::Events::Up) {
m_interactiveRange->panWithVector(0.0f, m_interactiveRange->yGridUnit());
m_contentView.curveView()->reload();
return true;
}
if (event == Ion::Events::Down) {
m_interactiveRange->panWithVector(0.0f, -m_interactiveRange->yGridUnit());
m_contentView.curveView()->reload();
return true;
}
if (event == Ion::Events::Left) {
m_interactiveRange->panWithVector(-m_interactiveRange->xGridUnit(), 0.0f);
m_contentView.curveView()->reload();
return true;
}
if (event == Ion::Events::Right) {
m_interactiveRange->panWithVector(m_interactiveRange->xGridUnit(), 0.0f);
m_contentView.curveView()->reload();
return true;
}
return false;
}
void ZoomParameterController::viewWillAppear() {
ViewController::viewWillAppear();
m_contentView.curveView()->setOkView(nullptr);

View File

@@ -1,25 +1,23 @@
#ifndef SHARED_ZOOM_PARAMETER_CONTROLLER_H
#define SHARED_ZOOM_PARAMETER_CONTROLLER_H
#include <escher.h>
#include "interactive_curve_view_range.h"
#include "curve_view.h"
#include "zoom_and_pan_curve_view_controller.h"
#include <apps/i18n.h>
namespace Shared {
class ZoomParameterController : public ViewController {
class ZoomParameterController : public ZoomAndPanCurveViewController {
public:
ZoomParameterController(Responder * parentResponder, InteractiveCurveViewRange * interactiveCurveViewRange, CurveView * curveView);
const char * title() override;
View * view() override;
bool handleEvent(Ion::Events::Event event) override;
View * view() override { return &m_contentView; }
void viewWillAppear() override;
void viewDidDisappear() override;
void didBecomeFirstResponder() override;
TELEMETRY_ID("Zoom");
private:
constexpr static KDCoordinate k_standardViewHeight = 175;
class ContentView : public View {
public:
constexpr static KDCoordinate k_legendHeight = 30;
@@ -46,7 +44,13 @@ private:
CurveView * m_curveView;
LegendView m_legendView;
};
void adaptCurveRange(bool viewWillAppear);
// ZoomAndPanCurveViewController
InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_interactiveRange; }
CurveView * curveView() override { return m_contentView.curveView(); }
ContentView m_contentView;
InteractiveCurveViewRange * m_interactiveRange;
};

View File

@@ -211,7 +211,16 @@ EquationStore::Error EquationStore::privateExactSolve(Poincare::Context * contex
// Step 3. Polynomial & Monovariable?
assert(numberOfVariables == 1 && numberOfDefinedModels() == 1);
Expression polynomialCoefficients[Expression::k_maxNumberOfPolynomialCoefficients];
int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context, replaceFunctionsButNotSymbols).getPolynomialReducedCoefficients(m_variables[0], polynomialCoefficients, context, updatedComplexFormat(context), preferences->angleUnit(), replaceFunctionsButNotSymbols ? ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions : ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
int degree = modelForRecord(definedRecordAtIndex(0))->standardForm(context, replaceFunctionsButNotSymbols)
.getPolynomialReducedCoefficients(
m_variables[0],
polynomialCoefficients,
context,
updatedComplexFormat(context),
preferences->angleUnit(),
replaceFunctionsButNotSymbols ?
ExpressionNode::SymbolicComputation::ReplaceDefinedFunctionsWithDefinitions :
ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition);
if (degree == 2) {
// Polynomial degree <= 2
m_type = Type::PolynomialMonovariable;
@@ -262,7 +271,9 @@ EquationStore::Error EquationStore::resolveLinearSystem(Expression exactSolution
Preferences::AngleUnit angleUnit = Preferences::sharedPreferences()->angleUnit();
// n unknown variables
int n = 0;
while (m_variables[n][0] != 0) { n++; }
while (n < Expression::k_maxNumberOfVariables && m_variables[n][0] != 0) {
n++;
}
int m = numberOfDefinedModels(); // m equations
/* Create the matrix (A | b) for the equation Ax=b */
Matrix Ab = Matrix::Builder();

View File

@@ -12,8 +12,4 @@ void BoxAxisView::drawRect(KDContext * ctx, KDRect rect) const {
drawLabelsAndGraduations(ctx, rect, Axis::Horizontal, false, false, true, k_axisMargin);
}
char * BoxAxisView::label(Axis axis, int index) const {
return axis == Axis::Vertical ? nullptr : (char *)m_labels[index];
}
}

View File

@@ -3,24 +3,21 @@
#include "box_range.h"
#include "store.h"
#include "../shared/curve_view.h"
#include "../shared/labeled_curve_view.h"
#include "../constant.h"
#include <poincare/print_float.h>
namespace Statistics {
class BoxAxisView : public Shared::CurveView {
class BoxAxisView : public Shared::HorizontallyLabeledCurveView {
public:
BoxAxisView(Store * store) :
CurveView(&m_boxRange),
m_labels{},
HorizontallyLabeledCurveView(&m_boxRange),
m_boxRange(BoxRange(store))
{}
void drawRect(KDContext * ctx, KDRect rect) const override;
private:
constexpr static KDCoordinate k_axisMargin = 3;
char * label(Axis axis, int index) const override;
char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
BoxRange m_boxRange;
};

View File

@@ -73,8 +73,8 @@ void BoxView::drawRect(KDContext * ctx, KDRect rect) const {
// Draw the horizontal lines linking the box to the extreme bounds
KDColor horizontalColor = isMainViewSelected() ? m_selectedHistogramColor : Palette::SecondaryText;
float segmentOrd = (lowBound + upBound)/ 2.0f;
drawSegment(ctx, rect, Axis::Horizontal, segmentOrd, minVal, firstQuart, horizontalColor);
drawSegment(ctx, rect, Axis::Horizontal, segmentOrd, thirdQuart, maxVal, horizontalColor);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, segmentOrd, minVal, firstQuart, horizontalColor);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Horizontal, segmentOrd, thirdQuart, maxVal, horizontalColor);
double calculations[5] = {minVal, firstQuart, m_store->median(m_series), thirdQuart, maxVal};
/* We then draw all the vertical lines of the box and then recolor the
@@ -83,10 +83,10 @@ void BoxView::drawRect(KDContext * ctx, KDRect rect) const {
* lines. This solution could hide the highlighted line by coloring the next
* quantile if it has the same value. */
for (int k = 0; k < 5; k++) {
drawSegment(ctx, rect, Axis::Vertical, calculations[k], lowBound, upBound, Palette::StatisticsBoxVerticalLine, k_quantileBarWidth);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, calculations[k], lowBound, upBound, Palette::StatisticsBoxVerticalLine, k_quantileBarWidth);
}
if (isMainViewSelected()) {
drawSegment(ctx, rect, Axis::Vertical, calculations[(int)*m_selectedQuantile], lowBound, upBound, Palette::StatisticsBox, k_quantileBarWidth);
drawHorizontalOrVerticalSegment(ctx, rect, Axis::Vertical, calculations[(int)*m_selectedQuantile], lowBound, upBound, Palette::StatisticsBox, k_quantileBarWidth);
}
}

View File

@@ -37,7 +37,6 @@ private:
static constexpr KDCoordinate k_quantileBarWidth = 2;
KDCoordinate boxLowerBoundPixel() const;
KDCoordinate boxUpperBoundPixel() const;
char * label(Axis axis, int index) const override { return nullptr; }
Store * m_store;
BoxRange m_boxRange;
int m_series;

View File

@@ -8,10 +8,9 @@ using namespace Shared;
namespace Statistics {
HistogramView::HistogramView(HistogramController * controller, Store * store, int series, Shared::BannerView * bannerView, KDColor selectedHistogramColor, KDColor notSelectedHistogramColor, KDColor selectedBarColor) :
CurveView(store, nullptr, bannerView, nullptr),
HorizontallyLabeledCurveView(store, nullptr, bannerView, nullptr),
m_controller(controller),
m_store(store),
m_labels{},
m_highlightedBarStart(NAN),
m_highlightedBarEnd(NAN),
m_series(series),
@@ -63,10 +62,6 @@ void HistogramView::setHighlight(float start, float end) {
}
}
char * HistogramView::label(Axis axis, int index) const {
return axis == Axis::Vertical ? nullptr : (char *)m_labels[index];
}
float HistogramView::EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context) {
Store * store = (Store *)model;
float totalSize = ((float *)context)[0];

View File

@@ -5,13 +5,13 @@
#include <poincare/print_float.h>
#include "store.h"
#include "../constant.h"
#include "../shared/curve_view.h"
#include "../shared/labeled_curve_view.h"
namespace Statistics {
class HistogramController;
class HistogramView : public Shared::CurveView {
class HistogramView : public Shared::HorizontallyLabeledCurveView {
public:
HistogramView(HistogramController * controller, Store * store, int series, Shared::BannerView * bannerView, KDColor selectedHistogramColor = Palette::StatisticsSelected, KDColor notSelectedHistogramColor = Palette::StatisticsNotSelected, KDColor selectedBarColor = Palette::StatisticsSelected);
int series() const { return m_series; }
@@ -21,10 +21,8 @@ public:
void setHighlight(float start, float end);
void setDisplayLabels(bool display) { m_displayLabels = display; }
private:
char * label(Axis axis, int index) const override;
HistogramController * m_controller;
Store * m_store;
char m_labels[k_maxNumberOfXLabels][k_labelBufferMaxSize];
static float EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context);
float m_highlightedBarStart;
float m_highlightedBarEnd;

View File

@@ -7,8 +7,8 @@ LEDS_CHOICE ?= 0
include build/defaults.mak
include build/platform.$(PLATFORM).mak
EPSILON_VERSION ?= 13.0.0
EPSILON_CUSTOM_VERSION ?= 1.19.1
EPSILON_VERSION ?= 13.2.0
EPSILON_CUSTOM_VERSION ?= 1.19.2
# USERNAME ?= N/A
EPSILON_APPS ?= calculation rpn graph code statistics probability solver atom sequence regression settings external
EPSILON_I18N ?= en fr es de pt hu
@@ -21,9 +21,6 @@ OMEGA_THEME ?= omega_light
ifndef USE_LIBA
$(error platform.mak should define USE_LIBA)
endif
ifndef EXE
$(error platform.mak should define EXE, the extension for executables)
endif
include build/toolchain.$(TOOLCHAIN).mak
SFLAGS += -DDEBUG=$(DEBUG)

View File

@@ -1,8 +1,10 @@
TOOLCHAIN = android
EXE = so
EPSILON_TELEMETRY ?= 1
ifdef NDK_ABI
BUILD_DIR := $(BUILD_DIR)/$(NDK_ABI)
ARCHS = armeabi-v7a arm64-v8a x86 x86_64
ifdef ARCH
EXE = so
BUILD_DIR := $(BUILD_DIR)/$(ARCH)
endif

View File

@@ -1,8 +1,15 @@
# Define standard compilation rules
.PHONY: official_authorization
ifeq ($(ACCEPT_OFFICIAL_TOS),1)
official_authorization:
@echo "CAUTION: You are about to build an official NumWorks firmware. Distribution of such firmware by a third party is prohibited. Are you sure you want to proceed? Please type "yes" to confirm." && read ans && [ $${ans:-no} = yes ]
else
official_authorization:
@echo "CAUTION: You are trying to build an official NumWorks firmware."
@echo "Distribution of such firmware by a third party is prohibited."
@echo "Please set the ACCEPT_OFFICIAL_TOS environment variable to proceed."
@exit -1
endif
$(eval $(call rule_for, \
AS, %.o, %.s, \
@@ -31,6 +38,12 @@ $(eval $(call rule_for, \
$$(CXX) $$(CXXFLAGS) $$(SFLAGS) -c $$< -o $$@ \
))
$(eval $(call rule_for, \
CPP, %, %.inc, \
$$(CPP) -P $$< $$@ \
))
ifdef EXE
ifeq ($(OS),Windows_NT)
# Work around command-line length limit
# On Msys2 the max command line is 32 000 characters. Our standard LD command
@@ -47,6 +60,7 @@ $(eval $(call rule_for, \
$$(LD) $$^ $$(LDFLAGS) -o $$@ \
))
endif
endif
$(eval $(call rule_for, \
WINDRES, %.o, %.rc, \

View File

@@ -29,32 +29,32 @@ all_official:
$(call file_check,$(ANDROID_GRADLE_PROPERTIES))
$(call file_check,$(IOS_MOBILE_PROVISION))
$(call command_check,$(EMCC))
$(Q) rm -rf output/stable_release
$(Q) mkdir -p output/stable_release
$(Q) rm -rf output/all_official
$(Q) mkdir -p output/all_official
$(Q) echo "BUILD_FIRMWARE DEVICE N0110"
$(Q) $(MAKE) clean
$(Q) $(MAKE) epsilon.official.onboarding.dfu
$(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0110.dfu
$(Q) cp output/release/device/n0110/epsilon.official.onboarding.dfu output/all_official/epsilon.device.n0110.dfu
$(Q) echo "BUILD_FIRMWARE DEVICE N0100"
$(Q) $(MAKE) MODEL=n0100 clean
$(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu
$(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/stable_release/epsilon.device.n0100.dfu
$(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/all_official/epsilon.device.n0100.dfu
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP"
$(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip
$(Q) cp output/release/simulator/web/simulator.official.zip output/stable_release/simulator.web.zip
$(Q) $(MAKE) PLATFORM=simulator TARGET=web clean
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web epsilon.official.zip
$(Q) cp output/release/simulator/web/epsilon.official.zip output/all_official/simulator.web.zip
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS"
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js
$(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.js
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web epsilon.official.js
$(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.js
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS"
$(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js
$(Q) cp output/release/simulator/web/epsilon.official.js output/stable_release/epsilon.python.js
$(Q) $(MAKE) PLATFORM=simulator TARGET=web clean
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js
$(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.python.js
$(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID"
$(Q) $(MAKE) PLATFORM=simulator TARGET=android clean
$(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.apk
$(Q) cp output/release/simulator/android/app/outputs/apk/release/android-release-unsigned.apk output/stable_release/epsilon.apk
$(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.signed.apk
$(Q) cp output/release/simulator/android/app/outputs/apk/codesigned/android-codesigned.apk output/all_official/epsilon.official.apk
$(Q) echo "BUILD_FIRMWARE SIMULATOR IOS"
$(Q) $(MAKE) PLATFORM=simulator TARGET=ios clean
$(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE="~/Downloads/NumWorks_Graphing_Calculator_Distribution.mobileprovision" output/release/simulator/ios/app/epsilon.official.ipa
$(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/stable_release/epsilon.ipa
$(Q) $(MAKE) PLATFORM=simulator TARGET=ios IOS_PROVISIONNING_PROFILE=$(IOS_MOBILE_PROVISION) output/release/simulator/ios/app/epsilon.official.ipa
$(Q) cp output/release/simulator/ios/app/epsilon.official.ipa output/all_official/epsilon.ipa

View File

@@ -20,28 +20,3 @@ $(BUILD_DIR)/test.external_flash.write.$(EXE): $(BUILD_DIR)/quiz/src/test_ion_ex
fi
$(Q) $(PYTHON) build/device/dfu.py -u $(word 1,$^)
.PHONY: %.two_binaries
%.two_binaries: %.elf
@echo "Building an internal and an external binary for $<"
$(Q) $(OBJCOPY) -O binary -j .text.external -j .rodata.external -j .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).external.bin
$(Q) $(OBJCOPY) -O binary -R .text.external -R .rodata.external -R .exam_mode_buffer $(BUILD_DIR)/$< $(BUILD_DIR)/$(basename $<).internal.bin
@echo "Padding $(basename $<).external.bin and $(basename $<).internal.bin"
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).external.bin
$(Q) printf "\xFF\xFF\xFF\xFF" >> $(BUILD_DIR)/$(basename $<).internal.bin
.PHONY: binpack
binpack:
rm -rf output/binpack
mkdir -p output/binpack
$(MAKE) clean
$(MAKE) $(BUILD_DIR)/flasher.light.bin
cp $(BUILD_DIR)/flasher.light.bin output/binpack
$(MAKE) $(BUILD_DIR)/bench.flash.bin
$(MAKE) $(BUILD_DIR)/bench.ram.bin
cp $(BUILD_DIR)/bench.ram.bin $(BUILD_DIR)/bench.flash.bin output/binpack
$(MAKE) epsilon.official.onboarding.update.two_binaries
cp $(BUILD_DIR)/epsilon.official.onboarding.update.internal.bin $(BUILD_DIR)/epsilon.official.onboarding.update.external.bin output/binpack
$(MAKE) clean
cd output && for binary in flasher.light.bin bench.flash.bin bench.ram.bin epsilon.official.onboarding.update.internal.bin epsilon.official.onboarding.update.external.bin; do shasum -a 256 -b binpack/$${binary} > binpack/$${binary}.sha256;done
cd output && tar cvfz binpack-`git rev-parse HEAD | head -c 7`.tgz binpack
rm -rf output/binpack

View File

@@ -0,0 +1,3 @@
ifndef ARCH
HANDY_TARGETS_EXTENSIONS += apk
endif

View File

@@ -1,6 +1,3 @@
$(BUILD_DIR)/epsilon%packed.js: EMSCRIPTEN_INIT_FILE = 0
HANDY_TARGETS_EXTENSIONS += zip
$(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0
$(BUILD_DIR)/epsilon.packed.js: $(call object_for,$(epsilon_src))
$(BUILD_DIR)/epsilon.official.packed.js: $(call object_for,$(epsilon_official_src))

View File

@@ -13,16 +13,16 @@ NDK_TOOLCHAIN_PATH = $(NDK_PATH)/toolchains/llvm/prebuilt/$(NDK_HOST_TAG)/bin
# is no toolchain for those archs on those API levels. Let's enforce NDK_VERSION
# at 21 for these archs, and 16 for the others.
ifeq ($(NDK_ABI),armeabi-v7a)
ifeq ($(ARCH),armeabi-v7a)
NDK_TARGET = armv7a-linux-androideabi
NDK_VERSION = 16
else ifeq ($(NDK_ABI),arm64-v8a)
else ifeq ($(ARCH),arm64-v8a)
NDK_TARGET = aarch64-linux-android
NDK_VERSION = 21
else ifeq ($(NDK_ABI),x86)
else ifeq ($(ARCH),x86)
NDK_TARGET = i686-linux-android
NDK_VERSION = 16
else ifeq ($(NDK_ABI),x86_64)
else ifeq ($(ARCH),x86_64)
NDK_TARGET = x86_64-linux-android
NDK_VERSION = 21
endif

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