[apps] Probability: redesigning the calculation controller (for future

scrolling purpose)
This commit is contained in:
Émilie Feral
2017-12-20 14:55:22 +01:00
committed by EmilieNumworks
parent 6ccabe2d3b
commit 8f4e9b9656
10 changed files with 344 additions and 276 deletions

View File

@@ -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\

View File

@@ -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();
}
}

View File

@@ -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];
};

View 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));
}
}

View 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

View File

@@ -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());
}
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);
}