mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[apps] Probability: redesigning the calculation controller (for future
scrolling purpose)
This commit is contained in:
committed by
EmilieNumworks
parent
6ccabe2d3b
commit
8f4e9b9656
@@ -9,6 +9,7 @@ app_objs += $(addprefix apps/probability/,\
|
||||
calculation/right_integral_calculation.o\
|
||||
calculation/finite_integral_calculation.o\
|
||||
calculation_controller.o\
|
||||
calculation_view.o\
|
||||
cell.o\
|
||||
image_table_view.o\
|
||||
law/binomial_law.o\
|
||||
|
||||
@@ -16,145 +16,39 @@ namespace Probability {
|
||||
|
||||
CalculationController::ContentView::ContentView(Responder * parentResponder, CalculationController * calculationController, Calculation * calculation, Law * law) :
|
||||
m_titleView(KDText::FontSize::Small, I18n::Message::ComputeProbability, 0.5f, 0.5f, Palette::GreyDark, Palette::WallScreen),
|
||||
m_lawCurveView(law, calculation),
|
||||
m_imageTableView(parentResponder, law, calculation, calculationController),
|
||||
m_draftTextBuffer{},
|
||||
m_calculation(calculation)
|
||||
m_calculationView(parentResponder, calculationController, calculation, law),
|
||||
m_lawCurveView(law, calculation)
|
||||
{
|
||||
for (int i = 0; i < k_maxNumberOfEditableFields; i++) {
|
||||
m_calculationCell[i].setParentResponder(parentResponder);
|
||||
m_calculationCell[i].textField()->setDelegate(calculationController);
|
||||
m_calculationCell[i].textField()->setDraftTextBuffer(m_draftTextBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
int CalculationController::ContentView::numberOfSubviews() const {
|
||||
return 2*m_calculation->numberOfParameters() + 3;
|
||||
return 3;
|
||||
}
|
||||
|
||||
View * CalculationController::ContentView::subviewAtIndex(int index) {
|
||||
assert(index >= 0 && index < 9);
|
||||
assert(index >= 0 && index < 3);
|
||||
if (index == 0) {
|
||||
return &m_titleView;
|
||||
}
|
||||
if (index == 1) {
|
||||
return &m_lawCurveView;
|
||||
}
|
||||
if (index == 2) {
|
||||
return &m_imageTableView;
|
||||
}
|
||||
if (index == 3) {
|
||||
m_text[0].setMessage(m_calculation->legendForParameterAtIndex(0));
|
||||
m_text[0].setAlignment(0.5f, 0.5f);
|
||||
return &m_text[0];
|
||||
}
|
||||
if (index == 5) {
|
||||
m_text[1].setMessage(m_calculation->legendForParameterAtIndex(1));
|
||||
m_text[1].setAlignment(0.5f, 0.5f);
|
||||
return &m_text[1];
|
||||
}
|
||||
if (index == 7) {
|
||||
m_text[2].setMessage(m_calculation->legendForParameterAtIndex(2));
|
||||
m_text[2].setAlignment(0.5f, 0.5f);
|
||||
return &m_text[2];
|
||||
}
|
||||
if (index == 4 || index == 6 || index == 8) {
|
||||
return &m_calculationCell[(index - 4)/2];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CalculationController::ContentView::willDisplayEditableCellAtIndex(int index) {
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
Complex<double>::convertFloatToText(m_calculation->parameterAtIndex(index), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal);
|
||||
m_calculationCell[index].textField()->setText(buffer);
|
||||
}
|
||||
|
||||
KDCoordinate CalculationController::ContentView::calculationCellWidth(int index) const {
|
||||
KDCoordinate calculationCellWidth = m_calculationCell[index].minimalSizeForOptimalDisplay().width();
|
||||
return min(k_maxTextFieldWidth, max(k_minTextFieldWidth, calculationCellWidth));
|
||||
}
|
||||
|
||||
void CalculationController::ContentView::updateCalculationLayout() {
|
||||
KDCoordinate titleHeight = KDText::charSize(KDText::FontSize::Small).height()+k_titleHeightMargin;
|
||||
KDSize charSize = KDText::charSize();
|
||||
KDCoordinate numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(0)));
|
||||
KDCoordinate xCoordinate = m_imageTableView.minimalSizeForOptimalDisplay().width() + 2*k_textWidthMargin+numberOfCharacters*charSize.width();
|
||||
markRectAsDirty(KDRect(xCoordinate, titleHeight+ImageTableView::k_totalMargin-1, bounds().width() - xCoordinate, ImageCell::k_height+2));
|
||||
|
||||
KDCoordinate calculationWidth = calculationCellWidth(0);
|
||||
m_calculationCell[0].setFrame(KDRect(xCoordinate, titleHeight+ImageTableView::k_totalMargin, calculationWidth, ImageCell::k_height));
|
||||
xCoordinate += calculationWidth + k_textWidthMargin;
|
||||
numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(1)));
|
||||
m_text[1].setFrame(KDRect(xCoordinate, titleHeight+ImageTableView::k_totalMargin, numberOfCharacters*charSize.width(), ImageCell::k_height));
|
||||
xCoordinate += numberOfCharacters*charSize.width() + k_textWidthMargin;
|
||||
calculationWidth = calculationCellWidth(1);
|
||||
m_calculationCell[1].setFrame(KDRect(xCoordinate, titleHeight+ImageTableView::k_totalMargin, calculationWidth, ImageCell::k_height));
|
||||
xCoordinate += calculationWidth + k_textWidthMargin;
|
||||
if (m_calculation->numberOfParameters() > 2) {
|
||||
numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(2)));;
|
||||
m_text[2].setFrame(KDRect(xCoordinate, titleHeight+ImageTableView::k_totalMargin, numberOfCharacters*charSize.width(), ImageCell::k_height));
|
||||
xCoordinate += numberOfCharacters*charSize.width() + k_textWidthMargin;
|
||||
calculationWidth = calculationCellWidth(2);
|
||||
m_calculationCell[2].setFrame(KDRect(xCoordinate, titleHeight+ImageTableView::k_totalMargin, calculationWidth, ImageCell::k_height));
|
||||
}
|
||||
return &m_calculationView;
|
||||
}
|
||||
|
||||
void CalculationController::ContentView::layoutSubviews() {
|
||||
markRectAsDirty(bounds());
|
||||
KDCoordinate titleHeight = KDText::charSize(KDText::FontSize::Small).height()+k_titleHeightMargin;
|
||||
m_titleView.setFrame(KDRect(0, 0, bounds().width(), titleHeight));
|
||||
KDSize charSize = KDText::charSize();
|
||||
KDCoordinate xCoordinate = 0;
|
||||
m_lawCurveView.setFrame(KDRect(0, titleHeight+ImageTableView::k_oneCellHeight, bounds().width(), bounds().height() - ImageTableView::k_oneCellHeight-titleHeight));
|
||||
KDSize tableSize = m_imageTableView.minimalSizeForOptimalDisplay();
|
||||
m_imageTableView.setFrame(KDRect(xCoordinate, titleHeight, tableSize));
|
||||
xCoordinate += tableSize.width() + k_textWidthMargin;
|
||||
KDCoordinate numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(0)));
|
||||
m_text[0].setFrame(KDRect(xCoordinate, titleHeight+ImageTableView::k_totalMargin, numberOfCharacters*charSize.width(), ImageCell::k_height));
|
||||
|
||||
for (int k = 0; k < m_calculation->numberOfParameters(); k++) {
|
||||
willDisplayEditableCellAtIndex(k);
|
||||
}
|
||||
updateCalculationLayout();
|
||||
}
|
||||
|
||||
void CalculationController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
KDCoordinate titleHeight = KDText::charSize(KDText::FontSize::Small).height()+k_titleHeightMargin;
|
||||
ctx->fillRect(KDRect(0,titleHeight, bounds().width(), ImageTableView::k_oneCellWidth), KDColorWhite);
|
||||
KDSize charSize = KDText::charSize();
|
||||
int numberOfCharacters;
|
||||
KDCoordinate xCoordinate = ImageTableView::k_oneCellWidth + k_textWidthMargin;
|
||||
for (int i = 0; i < k_maxNumberOfEditableFields; i++) {
|
||||
if (m_calculation->numberOfEditableParameters() == i) {
|
||||
return;
|
||||
}
|
||||
numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(i)));
|
||||
xCoordinate += numberOfCharacters*charSize.width() + k_textWidthMargin;
|
||||
|
||||
ctx->strokeRect(KDRect(xCoordinate-ImageTableView::k_outline, titleHeight+ImageTableView::k_margin, calculationCellWidth(i)+2*ImageTableView::k_outline, ImageCell::k_height+2*ImageTableView::k_outline), Palette::GreyMiddle);
|
||||
xCoordinate += calculationCellWidth(i) + k_textWidthMargin;
|
||||
}
|
||||
}
|
||||
|
||||
LawCurveView * CalculationController::ContentView::lawCurveView() {
|
||||
return &m_lawCurveView;
|
||||
}
|
||||
|
||||
ImageTableView * CalculationController::ContentView::imageTableView() {
|
||||
return &m_imageTableView;
|
||||
}
|
||||
|
||||
EditableTextCell * CalculationController::ContentView::calculationCellAtIndex(int index) {
|
||||
return &m_calculationCell[index];
|
||||
KDCoordinate calculationHeight = m_calculationView.minimalSizeForOptimalDisplay().height();
|
||||
m_calculationView.setFrame(KDRect(0, titleHeight, bounds().width(), bounds().height()-titleHeight));
|
||||
m_lawCurveView.setFrame(KDRect(0, titleHeight+calculationHeight, bounds().width(), bounds().height() - calculationHeight - titleHeight));
|
||||
}
|
||||
|
||||
CalculationController::CalculationController(Responder * parentResponder, Law * law, Calculation * calculation) :
|
||||
ViewController(parentResponder),
|
||||
m_contentView(this, this, calculation, law),
|
||||
m_calculation(calculation),
|
||||
m_contentView(this, this, m_calculation, law),
|
||||
m_law(law),
|
||||
m_highlightedSubviewIndex(1)
|
||||
m_law(law)
|
||||
{
|
||||
assert(law != nullptr);
|
||||
assert(calculation != nullptr);
|
||||
@@ -168,11 +62,15 @@ const char * CalculationController::title() {
|
||||
return m_titleBuffer;
|
||||
}
|
||||
|
||||
void CalculationController::reload() {
|
||||
m_contentView.layoutSubviews();
|
||||
void CalculationController::reloadLawCurveView() {
|
||||
m_contentView.lawCurveView()->reload();
|
||||
}
|
||||
|
||||
void CalculationController::reload() {
|
||||
m_contentView.calculationView()->reload();
|
||||
reloadLawCurveView();
|
||||
}
|
||||
|
||||
void CalculationController::setCalculationAccordingToIndex(int index, bool forceReinitialisation) {
|
||||
if ((int)m_calculation->type() == index && !forceReinitialisation) {
|
||||
return;
|
||||
@@ -195,103 +93,22 @@ void CalculationController::setCalculationAccordingToIndex(int index, bool force
|
||||
return;
|
||||
}
|
||||
m_calculation->setLaw(m_law);
|
||||
}
|
||||
|
||||
bool CalculationController::handleEvent(Ion::Events::Event event) {
|
||||
if ((event == Ion::Events::Left && m_highlightedSubviewIndex > 0) || (event == Ion::Events::Right && m_highlightedSubviewIndex < m_calculation->numberOfEditableParameters())) {
|
||||
if (m_highlightedSubviewIndex == 0) {
|
||||
m_contentView.imageTableView()->select(false);
|
||||
m_contentView.imageTableView()->setHighlight(false);
|
||||
} else {
|
||||
EditableTextCell * calculCell = m_contentView.calculationCellAtIndex(m_highlightedSubviewIndex-1);
|
||||
calculCell->setHighlighted(false);
|
||||
}
|
||||
m_highlightedSubviewIndex = event == Ion::Events::Left ? m_highlightedSubviewIndex - 1 : m_highlightedSubviewIndex + 1;
|
||||
if (m_highlightedSubviewIndex > 0) {
|
||||
EditableTextCell * newCalculCell = m_contentView.calculationCellAtIndex(m_highlightedSubviewIndex-1);
|
||||
newCalculCell->setHighlighted(true);
|
||||
app()->setFirstResponder(newCalculCell);
|
||||
} else {
|
||||
m_contentView.imageTableView()->setHighlight(true);
|
||||
app()->setFirstResponder(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if ((event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Down) && m_highlightedSubviewIndex == 0) {
|
||||
m_contentView.imageTableView()->select(true);
|
||||
app()->setFirstResponder(m_contentView.imageTableView());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CalculationController::textFieldDidHandleEvent(::TextField * textField, Ion::Events::Event event, bool returnValue) {
|
||||
m_contentView.updateCalculationLayout();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool CalculationController::textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) {
|
||||
return TextFieldDelegate::textFieldShouldFinishEditing(textField, event)
|
||||
|| (event == Ion::Events::Right && textField->cursorLocation() == textField->draftTextLength() && m_highlightedSubviewIndex < m_calculation->numberOfEditableParameters())
|
||||
|| (event == Ion::Events::Left && textField->cursorLocation() == 0);
|
||||
}
|
||||
|
||||
bool CalculationController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
|
||||
App * probaApp = (App *)app();
|
||||
Context * globalContext = probaApp->container()->globalContext();
|
||||
double floatBody = Expression::approximateToScalar<double>(text, *globalContext);
|
||||
if (std::isnan(floatBody) || std::isinf(floatBody)) {
|
||||
app()->displayWarning(I18n::Message::UndefinedValue);
|
||||
return false;
|
||||
}
|
||||
if (m_calculation->type() != Calculation::Type::FiniteIntegral && m_highlightedSubviewIndex == 2) {
|
||||
if (floatBody < 0.0) {
|
||||
floatBody = 0.0;
|
||||
}
|
||||
if (floatBody > 1.0) {
|
||||
floatBody = 1.0;
|
||||
}
|
||||
}
|
||||
if (!m_law->isContinuous() && (m_highlightedSubviewIndex == 1 || m_calculation->type() == Calculation::Type::FiniteIntegral)) {
|
||||
floatBody = std::round(floatBody);
|
||||
}
|
||||
m_calculation->setParameterAtIndex(floatBody, m_highlightedSubviewIndex-1);
|
||||
if (event == Ion::Events::Right || event == Ion::Events::Left) {
|
||||
handleEvent(event);
|
||||
}
|
||||
for (int k = 0; k < m_calculation->numberOfParameters(); k++) {
|
||||
m_contentView.willDisplayEditableCellAtIndex(k);
|
||||
}
|
||||
m_contentView.layoutSubviews();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CalculationController::viewWillAppear() {
|
||||
reload();
|
||||
}
|
||||
|
||||
void CalculationController::didBecomeFirstResponder() {
|
||||
void CalculationController::viewWillAppear() {
|
||||
reloadLawCurveView();
|
||||
m_contentView.calculationView()->selectSubview(1);
|
||||
}
|
||||
|
||||
void CalculationController::didEnterResponderChain(Responder * previousResponder) {
|
||||
App::Snapshot * snapshot = (App::Snapshot *)app()->snapshot();
|
||||
snapshot->setActivePage(App::Snapshot::Page::Calculations);
|
||||
updateTitle();
|
||||
for (int subviewIndex = 0; subviewIndex < ContentView::k_maxNumberOfEditableFields; subviewIndex++) {
|
||||
EditableTextCell * calculCell = m_contentView.calculationCellAtIndex(subviewIndex);
|
||||
calculCell->setHighlighted(false);
|
||||
}
|
||||
if (m_highlightedSubviewIndex > 0) {
|
||||
m_contentView.imageTableView()->select(false);
|
||||
m_contentView.imageTableView()->setHighlight(false);
|
||||
EditableTextCell * calculCell = m_contentView.calculationCellAtIndex(m_highlightedSubviewIndex-1);
|
||||
calculCell->setHighlighted(true);
|
||||
app()->setFirstResponder(calculCell);
|
||||
} else {
|
||||
m_contentView.imageTableView()->setHighlight(true);
|
||||
}
|
||||
}
|
||||
|
||||
void CalculationController::selectSubview(int subviewIndex) {
|
||||
m_highlightedSubviewIndex = subviewIndex;
|
||||
void CalculationController::didBecomeFirstResponder() {
|
||||
app()->setFirstResponder(m_contentView.calculationView());
|
||||
}
|
||||
|
||||
void CalculationController::updateTitle() {
|
||||
@@ -309,8 +126,4 @@ void CalculationController::updateTitle() {
|
||||
m_titleBuffer[currentChar-1] = 0;
|
||||
}
|
||||
|
||||
TextFieldDelegateApp * CalculationController::textFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,61 +4,46 @@
|
||||
#include <escher.h>
|
||||
#include "law/law.h"
|
||||
#include "law_curve_view.h"
|
||||
#include "image_table_view.h"
|
||||
#include "calculation_view.h"
|
||||
#include "calculation/calculation.h"
|
||||
#include "../shared/parameter_text_field_delegate.h"
|
||||
|
||||
namespace Probability {
|
||||
|
||||
class CalculationController : public ViewController, public Shared::ParameterTextFieldDelegate {
|
||||
class CalculationController : public ViewController {
|
||||
public:
|
||||
CalculationController(Responder * parentResponder, Law * law, Calculation * calculation);
|
||||
View * view() override;
|
||||
const char * title() override;
|
||||
void reload();
|
||||
void reloadLawCurveView();
|
||||
void setCalculationAccordingToIndex(int index, bool forceReinitialisation = false);
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void viewWillAppear() override;
|
||||
void didEnterResponderChain(Responder * previousResponder) override;
|
||||
void didBecomeFirstResponder() override;
|
||||
void selectSubview(int subviewIndex);
|
||||
bool textFieldDidHandleEvent(TextField * textField, Ion::Events::Event event, bool returnValue) override;
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
private:
|
||||
void updateTitle();
|
||||
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
|
||||
Calculation * m_calculation;
|
||||
class ContentView : public View {
|
||||
public:
|
||||
ContentView(Responder * parentResponder, CalculationController * calculationController, Calculation * Calculation, Law * law);
|
||||
void setCalculation(Calculation * calculation, int index);
|
||||
void layoutSubviews() override;
|
||||
void updateCalculationLayout();
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
LawCurveView * lawCurveView();
|
||||
ImageTableView * imageTableView();
|
||||
EditableTextCell * calculationCellAtIndex(int index);
|
||||
void willDisplayEditableCellAtIndex(int index);
|
||||
constexpr static int k_maxNumberOfEditableFields = 3;
|
||||
LawCurveView * lawCurveView() {
|
||||
return &m_lawCurveView;
|
||||
}
|
||||
CalculationView * calculationView() {
|
||||
return &m_calculationView;
|
||||
}
|
||||
private:
|
||||
constexpr static KDCoordinate k_minTextFieldWidth = 4*KDText::charSize().width();
|
||||
constexpr static KDCoordinate k_maxTextFieldWidth = 10*KDText::charSize().width();
|
||||
constexpr static KDCoordinate k_textWidthMargin = 5;
|
||||
constexpr static KDCoordinate k_titleHeightMargin = 5;
|
||||
int numberOfSubviews() const override;
|
||||
View * subviewAtIndex(int index) override;
|
||||
KDCoordinate calculationCellWidth(int index) const;
|
||||
void layoutSubviews() override;
|
||||
MessageTextView m_titleView;
|
||||
CalculationView m_calculationView;
|
||||
LawCurveView m_lawCurveView;
|
||||
ImageTableView m_imageTableView;
|
||||
MessageTextView m_text[k_maxNumberOfEditableFields];
|
||||
char m_draftTextBuffer[TextField::maxBufferSize()];
|
||||
EditableTextCell m_calculationCell[k_maxNumberOfEditableFields];
|
||||
Calculation * m_calculation;
|
||||
};
|
||||
ContentView m_contentView;
|
||||
Calculation * m_calculation;
|
||||
Law * m_law;
|
||||
int m_highlightedSubviewIndex;
|
||||
constexpr static int k_maxNumberOfTitleCharacters = 30;
|
||||
char m_titleBuffer[k_maxNumberOfTitleCharacters];
|
||||
};
|
||||
|
||||
217
apps/probability/calculation_view.cpp
Normal file
217
apps/probability/calculation_view.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
#include "calculation_view.h"
|
||||
#include "app.h"
|
||||
#include "../apps_container.h"
|
||||
#include "calculation_controller.h"
|
||||
#include <assert.h>
|
||||
|
||||
using namespace Poincare;
|
||||
using namespace Shared;
|
||||
|
||||
namespace Probability {
|
||||
|
||||
CalculationView::CalculationView(Responder * parentResponder, CalculationController * calculationController, Calculation * calculation, Law * law) :
|
||||
Responder(parentResponder),
|
||||
m_imageTableView(this, law, calculation, calculationController),
|
||||
m_draftTextBuffer{},
|
||||
m_law(law),
|
||||
m_calculation(calculation),
|
||||
m_highlightedSubviewIndex(1),
|
||||
m_calculationController(calculationController)
|
||||
{
|
||||
for (int i = 0; i < k_maxNumberOfEditableFields; i++) {
|
||||
m_calculationCell[i].setParentResponder(this);
|
||||
m_calculationCell[i].textField()->setDelegate(this);
|
||||
m_calculationCell[i].textField()->setDraftTextBuffer(m_draftTextBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CalculationView::didBecomeFirstResponder() {
|
||||
if (m_highlightedSubviewIndex > 0) {
|
||||
app()->setFirstResponder(&m_calculationCell[m_highlightedSubviewIndex-1]);
|
||||
} else {
|
||||
app()->setFirstResponder(&m_imageTableView);
|
||||
}
|
||||
}
|
||||
|
||||
bool CalculationView::handleEvent(Ion::Events::Event event) {
|
||||
if ((event == Ion::Events::Left && m_highlightedSubviewIndex > 0) || (event == Ion::Events::Right && m_highlightedSubviewIndex < m_calculation->numberOfEditableParameters())) {
|
||||
if (m_highlightedSubviewIndex == 0) {
|
||||
m_imageTableView.select(false);
|
||||
} else {
|
||||
m_calculationCell[m_highlightedSubviewIndex-1].setHighlighted(false);
|
||||
}
|
||||
m_highlightedSubviewIndex = event == Ion::Events::Left ? m_highlightedSubviewIndex - 1 : m_highlightedSubviewIndex + 1;
|
||||
if (m_highlightedSubviewIndex > 0) {
|
||||
m_calculationCell[m_highlightedSubviewIndex-1].setHighlighted(true);
|
||||
app()->setFirstResponder(&m_calculationCell[m_highlightedSubviewIndex-1]);
|
||||
} else {
|
||||
app()->setFirstResponder(&m_imageTableView);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CalculationView::selectSubview(int subviewIndex) {
|
||||
m_highlightedSubviewIndex = subviewIndex;
|
||||
}
|
||||
|
||||
bool CalculationView::textFieldDidHandleEvent(::TextField * textField, Ion::Events::Event event, bool returnValue) {
|
||||
updateCalculationLayout();
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
bool CalculationView::textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) {
|
||||
return TextFieldDelegate::textFieldShouldFinishEditing(textField, event)
|
||||
|| (event == Ion::Events::Right && textField->cursorLocation() == textField->draftTextLength() && m_highlightedSubviewIndex < m_calculation->numberOfEditableParameters())
|
||||
|| (event == Ion::Events::Left && textField->cursorLocation() == 0);
|
||||
}
|
||||
|
||||
bool CalculationView::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
|
||||
App * probaApp = (App *)app();
|
||||
Context * globalContext = probaApp->container()->globalContext();
|
||||
double floatBody = Expression::approximateToScalar<double>(text, *globalContext);
|
||||
if (std::isnan(floatBody) || std::isinf(floatBody)) {
|
||||
app()->displayWarning(I18n::Message::UndefinedValue);
|
||||
return false;
|
||||
}
|
||||
if (m_calculation->type() != Calculation::Type::FiniteIntegral && m_highlightedSubviewIndex == 2) {
|
||||
if (floatBody < 0.0) {
|
||||
floatBody = 0.0;
|
||||
}
|
||||
if (floatBody > 1.0) {
|
||||
floatBody = 1.0;
|
||||
}
|
||||
}
|
||||
if (!m_law->isContinuous() && (m_highlightedSubviewIndex == 1 || m_calculation->type() == Calculation::Type::FiniteIntegral)) {
|
||||
floatBody = std::round(floatBody);
|
||||
}
|
||||
m_calculation->setParameterAtIndex(floatBody, m_highlightedSubviewIndex-1);
|
||||
if (event == Ion::Events::Right || event == Ion::Events::Left) {
|
||||
handleEvent(event);
|
||||
}
|
||||
reloadData();
|
||||
updateCalculationLayout(); // TODO: updateCalculationLayout(0);
|
||||
m_calculationController->reloadLawCurveView();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CalculationView::reload() {
|
||||
markRectAsDirty(bounds());
|
||||
layoutSubviews();
|
||||
}
|
||||
|
||||
void CalculationView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
ctx->fillRect(KDRect(0,0, bounds().width(), ImageTableView::k_oneCellHeight), KDColorWhite);
|
||||
KDSize charSize = KDText::charSize();
|
||||
int numberOfCharacters;
|
||||
KDCoordinate xCoordinate = ImageTableView::k_oneCellWidth + k_textWidthMargin;
|
||||
for (int i = 0; i < k_maxNumberOfEditableFields; i++) {
|
||||
if (m_calculation->numberOfEditableParameters() == i) {
|
||||
return;
|
||||
}
|
||||
numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(i)));
|
||||
xCoordinate += numberOfCharacters*charSize.width() + k_textWidthMargin;
|
||||
|
||||
ctx->strokeRect(KDRect(xCoordinate-ImageTableView::k_outline, ImageTableView::k_margin, calculationCellWidth(i)+2*ImageTableView::k_outline, ImageCell::k_height+2*ImageTableView::k_outline), Palette::GreyMiddle);
|
||||
xCoordinate += calculationCellWidth(i) + k_textWidthMargin;
|
||||
}
|
||||
}
|
||||
|
||||
void CalculationView::willDisplayEditableCellAtIndex(int index) {
|
||||
m_calculationCell[index].setHighlighted(index == m_highlightedSubviewIndex-1);
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
Complex<double>::convertFloatToText(m_calculation->parameterAtIndex(index), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits, Expression::FloatDisplayMode::Decimal);
|
||||
m_calculationCell[index].textField()->setText(buffer);
|
||||
}
|
||||
|
||||
KDSize CalculationView::minimalSizeForOptimalDisplay() const {
|
||||
//xCoordinate += tableSize.width() + k_textWidthMargin;
|
||||
return KDSize(0, ImageTableView::k_oneCellHeight);
|
||||
}
|
||||
|
||||
TextFieldDelegateApp * CalculationView::textFieldDelegateApp() {
|
||||
return (App *)app();
|
||||
}
|
||||
|
||||
// TODO: add an index to reload only the right cells
|
||||
void CalculationView::updateCalculationLayout() {
|
||||
KDSize charSize = KDText::charSize();
|
||||
KDCoordinate numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(0)));
|
||||
KDCoordinate xCoordinate = m_imageTableView.minimalSizeForOptimalDisplay().width() + 2*k_textWidthMargin+numberOfCharacters*charSize.width();
|
||||
markRectAsDirty(KDRect(xCoordinate, ImageTableView::k_totalMargin-1, bounds().width() - xCoordinate, ImageCell::k_height+2));
|
||||
|
||||
KDCoordinate calculationWidth = calculationCellWidth(0);
|
||||
m_calculationCell[0].setFrame(KDRect(xCoordinate, ImageTableView::k_totalMargin, calculationWidth, ImageCell::k_height));
|
||||
xCoordinate += calculationWidth + k_textWidthMargin;
|
||||
numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(1)));
|
||||
m_text[1].setFrame(KDRect(xCoordinate, ImageTableView::k_totalMargin, numberOfCharacters*charSize.width(), ImageCell::k_height));
|
||||
xCoordinate += numberOfCharacters*charSize.width() + k_textWidthMargin;
|
||||
calculationWidth = calculationCellWidth(1);
|
||||
m_calculationCell[1].setFrame(KDRect(xCoordinate, ImageTableView::k_totalMargin, calculationWidth, ImageCell::k_height));
|
||||
xCoordinate += calculationWidth + k_textWidthMargin;
|
||||
if (m_calculation->numberOfParameters() > 2) {
|
||||
numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(2)));;
|
||||
m_text[2].setFrame(KDRect(xCoordinate, ImageTableView::k_totalMargin, numberOfCharacters*charSize.width(), ImageCell::k_height));
|
||||
xCoordinate += numberOfCharacters*charSize.width() + k_textWidthMargin;
|
||||
calculationWidth = calculationCellWidth(2);
|
||||
m_calculationCell[2].setFrame(KDRect(xCoordinate, ImageTableView::k_totalMargin, calculationWidth, ImageCell::k_height));
|
||||
}
|
||||
}
|
||||
|
||||
void CalculationView::reloadData() {
|
||||
for (int k = 0; k < m_calculation->numberOfParameters(); k++) {
|
||||
willDisplayEditableCellAtIndex(k);
|
||||
}
|
||||
}
|
||||
|
||||
int CalculationView::numberOfSubviews() const {
|
||||
return 2*m_calculation->numberOfParameters() + 1;
|
||||
}
|
||||
|
||||
View * CalculationView::subviewAtIndex(int index) {
|
||||
assert(index >= 0 && index < 7);
|
||||
if (index == 0) {
|
||||
return &m_imageTableView;
|
||||
}
|
||||
if (index == 1) {
|
||||
m_text[0].setMessage(m_calculation->legendForParameterAtIndex(0));
|
||||
m_text[0].setAlignment(0.5f, 0.5f);
|
||||
return &m_text[0];
|
||||
}
|
||||
if (index == 3) {
|
||||
m_text[1].setMessage(m_calculation->legendForParameterAtIndex(1));
|
||||
m_text[1].setAlignment(0.5f, 0.5f);
|
||||
return &m_text[1];
|
||||
}
|
||||
if (index == 5) {
|
||||
m_text[2].setMessage(m_calculation->legendForParameterAtIndex(2));
|
||||
m_text[2].setAlignment(0.5f, 0.5f);
|
||||
return &m_text[2];
|
||||
}
|
||||
if (index == 2 || index == 4 || index == 6) {
|
||||
return &m_calculationCell[(index - 2)/2];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CalculationView::layoutSubviews() {
|
||||
reloadData();
|
||||
|
||||
KDSize charSize = KDText::charSize();
|
||||
KDCoordinate xCoordinate = 0;
|
||||
KDSize tableSize = m_imageTableView.minimalSizeForOptimalDisplay();
|
||||
m_imageTableView.setFrame(KDRect(xCoordinate, 0, tableSize));
|
||||
xCoordinate += tableSize.width() + k_textWidthMargin;
|
||||
KDCoordinate numberOfCharacters = strlen(I18n::translate(m_calculation->legendForParameterAtIndex(0)));
|
||||
m_text[0].setFrame(KDRect(xCoordinate, ImageTableView::k_totalMargin, numberOfCharacters*charSize.width(), ImageCell::k_height));
|
||||
|
||||
updateCalculationLayout();
|
||||
}
|
||||
|
||||
KDCoordinate CalculationView::calculationCellWidth(int index) const {
|
||||
KDCoordinate calculationCellWidth = m_calculationCell[index].minimalSizeForOptimalDisplay().width();
|
||||
return min(k_maxTextFieldWidth, max(k_minTextFieldWidth, calculationCellWidth));
|
||||
}
|
||||
|
||||
}
|
||||
58
apps/probability/calculation_view.h
Normal file
58
apps/probability/calculation_view.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef PROBABILITY_CALCULATION_VIEW_H
|
||||
#define PROBABILITY_CALCULATION_VIEW_H
|
||||
|
||||
#include <escher.h>
|
||||
#include "law/law.h"
|
||||
#include "image_table_view.h"
|
||||
#include "calculation/calculation.h"
|
||||
#include "../shared/parameter_text_field_delegate.h"
|
||||
|
||||
namespace Probability {
|
||||
|
||||
class CalculationController;
|
||||
|
||||
class CalculationView : public View, public Responder, public Shared::ParameterTextFieldDelegate {
|
||||
public:
|
||||
CalculationView(Responder * parentResponder, CalculationController * calculationController, Calculation * Calculation, Law * law);
|
||||
/* Responder */
|
||||
void didBecomeFirstResponder() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void selectSubview(int subviewIndex);
|
||||
|
||||
/* TextField delegate */
|
||||
bool textFieldDidHandleEvent(TextField * textField, Ion::Events::Event event, bool returnValue) override;
|
||||
bool textFieldShouldFinishEditing(TextField * textField, Ion::Events::Event event) override;
|
||||
bool textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) override;
|
||||
|
||||
/* View */
|
||||
void reload();
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
void willDisplayEditableCellAtIndex(int index);
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
constexpr static int k_maxNumberOfEditableFields = 3;
|
||||
private:
|
||||
constexpr static KDCoordinate k_minTextFieldWidth = 4*KDText::charSize().width();
|
||||
constexpr static KDCoordinate k_maxTextFieldWidth = 10*KDText::charSize().width();
|
||||
constexpr static KDCoordinate k_textWidthMargin = 5;
|
||||
Shared::TextFieldDelegateApp * textFieldDelegateApp() override;
|
||||
void updateCalculationLayout();
|
||||
void reloadData();
|
||||
int numberOfSubviews() const override;
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
KDCoordinate calculationCellWidth(int index) const;
|
||||
ImageTableView m_imageTableView;
|
||||
MessageTextView m_text[k_maxNumberOfEditableFields];
|
||||
char m_draftTextBuffer[TextField::maxBufferSize()];
|
||||
EditableTextCell m_calculationCell[k_maxNumberOfEditableFields];
|
||||
Law * m_law;
|
||||
Calculation * m_calculation;
|
||||
int m_highlightedSubviewIndex;
|
||||
CalculationController * m_calculationController;
|
||||
};
|
||||
|
||||
/*class ScrollableCalculationView : public ScrollableView, public ScrollView
|
||||
}*/
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -68,27 +68,29 @@ KDSize ImageTableView::minimalSizeForOptimalDisplay() const {
|
||||
|
||||
void ImageTableView::didBecomeFirstResponder() {
|
||||
m_selectableTableView.reloadData();
|
||||
m_isSelected = true;
|
||||
if (selectedRow() == -1) {
|
||||
selectCellAtLocation(0, 0);
|
||||
} else {
|
||||
selectCellAtLocation(selectedColumn(), selectedRow());
|
||||
}
|
||||
app()->setFirstResponder(&m_selectableTableView);
|
||||
}
|
||||
|
||||
void ImageTableView::didEnterResponderChain(Responder * previousFirstResponder) {
|
||||
selectCellAtLocation(0, 0);
|
||||
}
|
||||
|
||||
void ImageTableView::willExitResponderChain(Responder * nextFirstResponder) {
|
||||
m_calculationController->reload();
|
||||
m_selectableTableView.deselectTable();
|
||||
}
|
||||
|
||||
bool ImageTableView::handleEvent(Ion::Events::Event event) {
|
||||
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
|
||||
if ((event == Ion::Events::OK || event == Ion::Events::EXE || event == Ion::Events::Down) && !m_isSelected) {
|
||||
select(true);
|
||||
return true;
|
||||
}
|
||||
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && m_isSelected) {
|
||||
m_calculationController->setCalculationAccordingToIndex(selectedRow());
|
||||
hideDropdown();
|
||||
select(false);
|
||||
return true;
|
||||
}
|
||||
if (event == Ion::Events::Back) {
|
||||
hideDropdown();
|
||||
select(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -98,21 +100,18 @@ void ImageTableView::select(bool select) {
|
||||
if (!select) {
|
||||
m_selectableTableView.deselectTable();
|
||||
m_isSelected = select;
|
||||
m_selectableTableView.reloadCellAtLocation(0, 0);
|
||||
m_selectableTableView.reloadData();
|
||||
/* The dropdown menu is drawn on the law curve view, so when we deselect
|
||||
* the dropdown menu, we need to redraw the law curve view */
|
||||
m_calculationController->reload();
|
||||
m_selectableTableView.selectCellAtLocation(0, 0);
|
||||
} else {
|
||||
m_isSelected = select;
|
||||
m_selectableTableView.reloadData();
|
||||
m_selectableTableView.selectCellAtLocation(0, (int)m_calculation->type());
|
||||
}
|
||||
}
|
||||
|
||||
void ImageTableView::setHighlight(bool highlight) {
|
||||
if (highlight) {
|
||||
m_selectableTableView.selectCellAtLocation(0,0);
|
||||
} else {
|
||||
m_selectableTableView.deselectTable();
|
||||
}
|
||||
}
|
||||
|
||||
int ImageTableView::numberOfRows() {
|
||||
if (m_isSelected) {
|
||||
if (m_law->isContinuous()) {
|
||||
@@ -123,6 +122,10 @@ int ImageTableView::numberOfRows() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
KDCoordinate ImageTableView::cellHeight() {
|
||||
return ImageCell::k_height;
|
||||
}
|
||||
|
||||
HighlightCell * ImageTableView::reusableCell(int index) {
|
||||
assert(index >= 0);
|
||||
assert(index < k_numberOfImages);
|
||||
@@ -145,10 +148,6 @@ void ImageTableView::willDisplayCellForIndex(HighlightCell * cell, int index) {
|
||||
myCell->reloadCell();
|
||||
}
|
||||
|
||||
KDCoordinate ImageTableView::cellHeight() {
|
||||
return ImageCell::k_height;
|
||||
}
|
||||
|
||||
int ImageTableView::numberOfSubviews() const {
|
||||
return 1;
|
||||
}
|
||||
@@ -162,12 +161,4 @@ void ImageTableView::layoutSubviews() {
|
||||
m_selectableTableView.setFrame(KDRect(k_totalMargin, k_totalMargin, bounds().width()-2*k_totalMargin, bounds().height()-k_totalMargin));
|
||||
}
|
||||
|
||||
void ImageTableView::hideDropdown() {
|
||||
select(false);
|
||||
setHighlight(true);
|
||||
m_selectableTableView.reloadData();
|
||||
m_calculationController->reload();
|
||||
app()->setFirstResponder(parentResponder());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,16 +29,16 @@ public:
|
||||
ImageTableView(Responder * parentResponder, Law * law, Calculation * calculation, CalculationController * calculationController);
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
KDSize minimalSizeForOptimalDisplay() const override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void didBecomeFirstResponder() override;
|
||||
void didEnterResponderChain(Responder * previousFirstResponder) override;
|
||||
void willExitResponderChain(Responder * nextFirstResponder) override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void select(bool select);
|
||||
void setHighlight(bool highlight);
|
||||
int numberOfRows() override;
|
||||
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
|
||||
KDCoordinate cellHeight() override;
|
||||
HighlightCell * reusableCell(int index) override;
|
||||
int reusableCellCount() override;
|
||||
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
|
||||
constexpr static KDCoordinate k_outline = 1;
|
||||
constexpr static KDCoordinate k_margin = 3;
|
||||
constexpr static KDCoordinate k_totalMargin = k_outline+k_margin;
|
||||
@@ -48,8 +48,6 @@ private:
|
||||
int numberOfSubviews() const override;
|
||||
View * subviewAtIndex(int index) override;
|
||||
void layoutSubviews() override;
|
||||
void setCalculationAccordingToIndex(int index);
|
||||
void hideDropdown();
|
||||
constexpr static int k_numberOfImages = 4;
|
||||
ImageCell m_imageCells[k_numberOfImages];
|
||||
SelectableTableView m_selectableTableView;
|
||||
|
||||
@@ -15,6 +15,11 @@ LawCurveView::LawCurveView(Law * law, Calculation * calculation) :
|
||||
assert(calculation != nullptr);
|
||||
}
|
||||
|
||||
void LawCurveView::reload() {
|
||||
CurveView::reload();
|
||||
markRectAsDirty(bounds());
|
||||
}
|
||||
|
||||
void LawCurveView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
float lowerBound = m_calculation->lowerBound();
|
||||
float upperBound = m_calculation->upperBound();
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Probability {
|
||||
class LawCurveView : public Shared::CurveView {
|
||||
public:
|
||||
LawCurveView(Law * law, Calculation * calculation);
|
||||
void reload() override;
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
protected:
|
||||
char * label(Axis axis, int index) const override;
|
||||
|
||||
@@ -155,7 +155,6 @@ bool ParametersController::textFieldDidFinishEditing(TextField * textField, cons
|
||||
}
|
||||
|
||||
void ParametersController::buttonAction() {
|
||||
m_calculationController->selectSubview(1);
|
||||
StackViewController * stack = stackController();
|
||||
stack->push(m_calculationController, KDColorWhite, Palette::SubTab, Palette::SubTab);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user