From 8f4e9b96562ced9d3b80d7dd3292c59172ed1556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milie=20Feral?= Date: Wed, 20 Dec 2017 14:55:22 +0100 Subject: [PATCH] [apps] Probability: redesigning the calculation controller (for future scrolling purpose) --- apps/probability/Makefile | 1 + apps/probability/calculation_controller.cpp | 235 ++------------------ apps/probability/calculation_controller.h | 41 ++-- apps/probability/calculation_view.cpp | 217 ++++++++++++++++++ apps/probability/calculation_view.h | 58 +++++ apps/probability/image_table_view.cpp | 53 ++--- apps/probability/image_table_view.h | 8 +- apps/probability/law_curve_view.cpp | 5 + apps/probability/law_curve_view.h | 1 + apps/probability/parameters_controller.cpp | 1 - 10 files changed, 344 insertions(+), 276 deletions(-) create mode 100644 apps/probability/calculation_view.cpp create mode 100644 apps/probability/calculation_view.h diff --git a/apps/probability/Makefile b/apps/probability/Makefile index 93fcdbb02..00cb1496f 100644 --- a/apps/probability/Makefile +++ b/apps/probability/Makefile @@ -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\ diff --git a/apps/probability/calculation_controller.cpp b/apps/probability/calculation_controller.cpp index cabfc447f..14adf9f6a 100644 --- a/apps/probability/calculation_controller.cpp +++ b/apps/probability/calculation_controller.cpp @@ -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::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(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(); -} - } diff --git a/apps/probability/calculation_controller.h b/apps/probability/calculation_controller.h index f95e87283..73dd02b63 100644 --- a/apps/probability/calculation_controller.h +++ b/apps/probability/calculation_controller.h @@ -4,61 +4,46 @@ #include #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]; }; diff --git a/apps/probability/calculation_view.cpp b/apps/probability/calculation_view.cpp new file mode 100644 index 000000000..ceebb8de5 --- /dev/null +++ b/apps/probability/calculation_view.cpp @@ -0,0 +1,217 @@ +#include "calculation_view.h" +#include "app.h" +#include "../apps_container.h" +#include "calculation_controller.h" +#include + +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(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::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)); +} + +} diff --git a/apps/probability/calculation_view.h b/apps/probability/calculation_view.h new file mode 100644 index 000000000..a6677eba5 --- /dev/null +++ b/apps/probability/calculation_view.h @@ -0,0 +1,58 @@ +#ifndef PROBABILITY_CALCULATION_VIEW_H +#define PROBABILITY_CALCULATION_VIEW_H + +#include +#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 diff --git a/apps/probability/image_table_view.cpp b/apps/probability/image_table_view.cpp index 56a62317c..379f4d627 100644 --- a/apps/probability/image_table_view.cpp +++ b/apps/probability/image_table_view.cpp @@ -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()); -} - } diff --git a/apps/probability/image_table_view.h b/apps/probability/image_table_view.h index 20a046250..1b303e5d4 100644 --- a/apps/probability/image_table_view.h +++ b/apps/probability/image_table_view.h @@ -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; diff --git a/apps/probability/law_curve_view.cpp b/apps/probability/law_curve_view.cpp index b4584c0b1..07dd3b6b9 100644 --- a/apps/probability/law_curve_view.cpp +++ b/apps/probability/law_curve_view.cpp @@ -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(); diff --git a/apps/probability/law_curve_view.h b/apps/probability/law_curve_view.h index 402c54ea1..d1d8b3410 100644 --- a/apps/probability/law_curve_view.h +++ b/apps/probability/law_curve_view.h @@ -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; diff --git a/apps/probability/parameters_controller.cpp b/apps/probability/parameters_controller.cpp index 6d55c1f40..19ccb36d4 100644 --- a/apps/probability/parameters_controller.cpp +++ b/apps/probability/parameters_controller.cpp @@ -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); }