[poincare] Adapt CharLayoutNode and HorizontalLayoutNode

This commit is contained in:
Léa Saviot
2018-07-03 10:02:29 +02:00
parent d53abf5bf1
commit 049cf772e2
11 changed files with 325 additions and 123 deletions

View File

@@ -3,6 +3,14 @@ SFLAGS += -Ipoincare/include
#include poincare/src/simplify/Makefile
#include poincare/src/simplification/Makefile
objs += $(addprefix poincare/src/,\
char_layout_node.o\
horizontal_layout_node.o\
layout_cursor.o\
layout_node.o\
layout_reference.o\
)
objs += $(addprefix poincare/src/,\
absolute_value.o\
addition.o\
@@ -47,10 +55,7 @@ objs += $(addprefix poincare/src/,\
imaginary_part.o\
integer.o\
integral.o\
layout_cursor.o\
layout_engine.o\
layout_node.o\
layout_reference.o\
list_data.o\
least_common_multiple.o\
logarithm.o\

View File

@@ -8,11 +8,28 @@ namespace Poincare {
class AllocationFailedLayoutNode : public LayoutNode {
public:
// LayoutNode
int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override {
assert(false);
return 0;
}
// TreeNode
size_t size() const override { return sizeof(AllocationFailedLayoutNode); }
const char * description() const override { return "Allocation Failed"; }
int numberOfChildren() const override { return 0; }
bool isAllocationFailure() const override { return true; }
protected:
// LayoutNode
void computeSize() override { m_sized = true; }
void computeBaseline() override { m_baselined = true; }
KDPoint positionOfChild(LayoutNode * child) override {
assert(false);
return KDPointZero;
}
private:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override {}
};
class AllocationFailedLayoutRef : public LayoutReference<AllocationFailedLayoutNode> {

View File

@@ -1,59 +1,64 @@
#ifndef POINCARE_CHAR_LAYOUT_NODE_H
#define POINCARE_CHAR_LAYOUT_NODE_H
#include <poincare/layout_reference.h>
#include <poincare/layout_node.h>
#include <poincare/layout_cursor.h>
#include <poincare/layout_engine.h>
#include <poincare/layout_node.h>
#include <poincare/layout_reference.h>
namespace Poincare {
class CharLayoutNode : public LayoutNode {
public:
CharLayoutNode() : LayoutNode() {}
size_t size() const override {
return sizeof(CharLayoutNode);
}
CharLayoutNode() :
LayoutNode(),
m_char('a'),
m_fontSize(KDText::FontSize::Large)
{}
void setChar(char c) { m_char = c; }
void setFontSize(KDText::FontSize fontSize) { m_fontSize = fontSize; }
// LayoutNode
int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override {
return LayoutEngine::writeOneCharInBuffer(buffer, bufferSize, m_char);
}
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
// TreeNode
size_t size() const override { return sizeof(CharLayoutNode); }
int numberOfChildren() const override { return 0; }
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override {
if (cursor->position() == LayoutCursor::Position::Right) {
cursor->setPosition(LayoutCursor::Position::Left);
return;
}
LayoutNode * parentNode = parent();
if (parentNode != nullptr) {
parentNode->moveCursorLeft(cursor, shouldRecomputeLayout);
}
}
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override {
if (cursor->position() == LayoutCursor::Position::Left) {
cursor->setPosition(LayoutCursor::Position::Right);
return;
}
LayoutNode * parentNode = parent();
if (parentNode != nullptr) {
parentNode->moveCursorRight(cursor, shouldRecomputeLayout);
}
}
#if TREE_LOG
const char * description() const override {
static char Description[] = "Char a";
Description[5] = m_char;
return Description;
}
#endif
protected:
// LayoutNode
void computeSize() override;
void computeBaseline() override;
KDPoint positionOfChild(LayoutNode * child) override {
assert(false);
return KDPointZero;
}
void setChar(char c) { m_char = c; }
private:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override;
char m_char;
KDText::FontSize m_fontSize;
};
class CharLayoutRef : public LayoutReference<CharLayoutNode> {
public:
CharLayoutRef(char c) : LayoutReference<CharLayoutNode>() {
CharLayoutRef(char c, KDText::FontSize fontSize = KDText::FontSize::Large) :
LayoutReference<CharLayoutNode>()
{
if (!(this->node()->isAllocationFailure())) {
this->typedNode()->setChar(c);
this->typedNode()->setFontSize(fontSize);
}
}
};

View File

@@ -7,6 +7,9 @@
namespace Poincare {
/* WARNING: A HorizontalLayout should never have a HorizontalLayout child. For
* instance, use addOrMergeChildAtIndex to add a LayoutNode safely. */
class HorizontalLayoutNode : public LayoutNode {
public:
HorizontalLayoutNode() :
@@ -14,72 +17,34 @@ public:
m_numberOfChildren(0)
{}
size_t size() const override {
return sizeof(HorizontalLayoutNode);
}
// LayoutNode
int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const override;
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override;
// TreeNode
size_t size() const override { return sizeof(HorizontalLayoutNode); }
int numberOfChildren() const override { return m_numberOfChildren; }
void incrementNumberOfChildren(int increment = 1) override { m_numberOfChildren+= increment; }
void decrementNumberOfChildren(int decrement = 1) override {
assert(m_numberOfChildren > 0);
assert(m_numberOfChildren >= decrement);
m_numberOfChildren-= decrement;
}
void eraseNumberOfChildren() override {
m_numberOfChildren = 0;
}
void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) override {
if (this == cursor->layoutReference().node()) {
if (cursor->position() == LayoutCursor::Position::Left) {
// Case: Left. Ask the parent.
LayoutNode * parentNode = parent();
if (parentNode != nullptr) {
parentNode->moveCursorLeft(cursor, shouldRecomputeLayout);
}
return;
}
assert(cursor->position() == LayoutCursor::Position::Right);
/* Case: Right. Go to the last child if there is one, and move Left. Else
* go Left and ask the parent. */
int childrenCount = numberOfChildren();
if (childrenCount >= 1) {
cursor->setLayoutNode(static_cast<LayoutNode *>(childTreeAtIndex(childrenCount-1)));
} else {
cursor->setPosition(LayoutCursor::Position::Left);
}
return cursor->moveLeft(shouldRecomputeLayout);
}
// Case: The cursor is Left of a child.
assert(cursor->position() == LayoutCursor::Position::Left);
int childIndex = indexOfChildByIdentifier(cursor->layoutIdentifier());
assert(childIndex >= 0);
if (childIndex == 0) {
// Case: the child is the leftmost. Ask the parent.
if (parent()) {
cursor->setLayoutNode(this);
return cursor->moveLeft(shouldRecomputeLayout);
}
return;
}
// Case: the child is not the leftmost. Go to its left sibling and move Left.
cursor->setLayoutNode(static_cast<LayoutNode *>(childTreeAtIndex(childIndex-1)));
cursor->setPosition(LayoutCursor::Position::Right);
cursor->moveLeft(shouldRecomputeLayout);
}
void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) override {
//TODO
LayoutNode * parentNode = parent();
if (parentNode != nullptr) {
parentNode->moveCursorRight(cursor, shouldRecomputeLayout);
}
}
void eraseNumberOfChildren() override { m_numberOfChildren = 0; }
#if TREE_LOG
const char * description() const override {
return "Horizontal Layout";
}
#endif
protected:
// LayoutNode
void computeSize() override;
void computeBaseline() override;
KDPoint positionOfChild(LayoutNode * l) override;
private:
void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) override {}
int m_numberOfChildren;
};

View File

@@ -49,7 +49,7 @@ public:
bool isEquivalentTo(LayoutCursor cursor);
/* Position */
int middleLeftPoint();
KDPoint middleLeftPoint();
/* Move */
void moveLeft(bool * shouldRecomputeLayout);

View File

@@ -1,7 +1,9 @@
#ifndef POINCARE_LAYOUT_NODE_H
#define POINCARE_LAYOUT_NODE_H
#include "tree_node.h"
#include <poincare/print_float.h>
#include <poincare/tree_node.h>
#include <kandinsky.h>
namespace Poincare {
@@ -9,6 +11,30 @@ class LayoutCursor;
class LayoutNode : public TreeNode {
public:
// Constructor
LayoutNode() :
TreeNode(),
m_baseline(0),
m_frame(KDRectZero),
m_baselined(false),
m_positioned(false),
m_sized(false)
{
}
// Rendering
void draw(KDContext * ctx, KDPoint p, KDColor expressionColor = KDColorBlack, KDColor backgroundColor = KDColorWhite);
KDPoint origin();
KDPoint absoluteOrigin();
KDSize layoutSize();
KDCoordinate baseline();
virtual void invalidAllSizesPositionsAndBaselines();
// Serialization
virtual int writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits = PrintFloat::k_numberOfStoredSignificantDigits) const = 0;
// TreeNode
static TreeNode * FailedAllocationStaticNode();
TreeNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); }
static int AllocationFailureNodeIdentifier() {
@@ -18,15 +44,10 @@ public:
return AllocationFailureNodeIdentifier();
}
/* Hierarchy */
// Hierarchy
LayoutNode * parent() const { return static_cast<LayoutNode *>(parentTree()); }
/* Rendering */
void draw();
int origin();
int absoluteOrigin();
/* Tree navigation */
// Tree navigation
virtual void moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) {}
virtual void moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) {}
virtual void moveCursorUp(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited = false) {}
@@ -36,6 +57,7 @@ public:
LayoutNode * childAtIndex(int i) { return static_cast<LayoutNode *>(childTreeAtIndex(i)); }
protected:
// Iterators
class Iterator {
public:
Iterator(LayoutNode * node) : m_node(node) {}
@@ -62,8 +84,21 @@ protected:
};
DirectChildren children() { return DirectChildren(this); }
// Sizing and positioning
virtual void computeSize() = 0;
virtual void computeBaseline() = 0;
virtual KDPoint positionOfChild(LayoutNode * child) = 0;
/* m_baseline is the signed vertical distance from the top of the layout to
* the fraction bar of an hypothetical fraction sibling layout. If the top of
* the layout is under that bar, the baseline is negative. */
KDCoordinate m_baseline;
KDRect m_frame;
bool m_baselined;
bool m_positioned;
bool m_sized;
private:
virtual void render() {};
virtual void render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) = 0;
};
}

View File

@@ -33,11 +33,11 @@ public:
TreeReference<T>::replaceChildAtIndex(oldChildIndex, newChild);
}
int layoutOrigin() {
KDPoint layoutOrigin() {
return this->typedNode()->layoutOrigin();
}
int absoluteOrigin() {
KDPoint absoluteOrigin() {
return this->typedNode()->absoluteOrigin();
}
};

View File

@@ -0,0 +1,45 @@
#include <poincare/char_layout_node.h>
namespace Poincare {
void CharLayoutNode::moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) {
if (cursor->position() == LayoutCursor::Position::Right) {
cursor->setPosition(LayoutCursor::Position::Left);
return;
}
LayoutNode * parentNode = parent();
if (parentNode != nullptr) {
parentNode->moveCursorLeft(cursor, shouldRecomputeLayout);
}
}
void CharLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) {
if (cursor->position() == LayoutCursor::Position::Left) {
cursor->setPosition(LayoutCursor::Position::Right);
return;
}
LayoutNode * parentNode = parent();
if (parentNode != nullptr) {
parentNode->moveCursorRight(cursor, shouldRecomputeLayout);
}
}
// Sizing and positioning
void CharLayoutNode::computeSize() {
assert(!m_sized);
m_frame.setSize(KDText::charSize(m_fontSize));
m_sized = true;
}
void CharLayoutNode::computeBaseline() {
assert(!m_baselined);
m_baseline = (KDText::charSize(m_fontSize).height()+1)/2; //TODO +1 ?
m_baselined = true;
}
void CharLayoutNode::render(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
char string[2] = {m_char, 0};
ctx->drawString(string, p, m_fontSize, expressionColor, backgroundColor);
}
}

View File

@@ -0,0 +1,104 @@
#include <poincare/horizontal_layout_node.h>
#include <poincare/layout_engine.h>
namespace Poincare {
static inline KDCoordinate max(KDCoordinate c1, KDCoordinate c2) { return c1 > c2 ? c1 : c2; }
int HorizontalLayoutNode::writeTextInBuffer(char * buffer, int bufferSize, int numberOfSignificantDigits) const {
if (numberOfChildren() == 0) {
if (bufferSize == 0) {
return -1;
}
buffer[0] = 0;
return 0;
}
return LayoutEngine::writeInfixExpressionLayoutTextInBuffer(this, buffer, bufferSize, numberOfSignificantDigits, "");
}
void HorizontalLayoutNode::moveCursorLeft(LayoutCursor * cursor, bool * shouldRecomputeLayout) {
if (this == cursor->layoutReference().node()) {
if (cursor->position() == LayoutCursor::Position::Left) {
// Case: Left. Ask the parent.
LayoutNode * parentNode = parent();
if (parentNode != nullptr) {
parentNode->moveCursorLeft(cursor, shouldRecomputeLayout);
}
return;
}
assert(cursor->position() == LayoutCursor::Position::Right);
/* Case: Right. Go to the last child if there is one, and move Left. Else
* go Left and ask the parent. */
int childrenCount = numberOfChildren();
if (childrenCount >= 1) {
cursor->setLayoutNode(static_cast<LayoutNode *>(childTreeAtIndex(childrenCount-1)));
} else {
cursor->setPosition(LayoutCursor::Position::Left);
}
return cursor->moveLeft(shouldRecomputeLayout);
}
// Case: The cursor is Left of a child.
assert(cursor->position() == LayoutCursor::Position::Left);
int childIndex = indexOfChildByIdentifier(cursor->layoutIdentifier());
assert(childIndex >= 0);
if (childIndex == 0) {
// Case: the child is the leftmost. Ask the parent.
if (parent()) {
cursor->setLayoutNode(this);
return cursor->moveLeft(shouldRecomputeLayout);
}
return;
}
// Case: the child is not the leftmost. Go to its left sibling and move Left.
cursor->setLayoutNode(static_cast<LayoutNode *>(childTreeAtIndex(childIndex-1)));
cursor->setPosition(LayoutCursor::Position::Right);
cursor->moveLeft(shouldRecomputeLayout);
}
void HorizontalLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecomputeLayout) {
//TODO
LayoutNode * parentNode = parent();
if (parentNode != nullptr) {
parentNode->moveCursorRight(cursor, shouldRecomputeLayout);
}
}
KDSize HorizontalLayoutNode::computeSize() {
assert(!m_sized);
KDCoordinate totalWidth = 0;
KDCoordinate maxUnderBaseline = 0;
KDCoordinate maxAboveBaseline = 0;
for (LayoutNode * l : directChildren()) {
KDSize childSize = l->size();
totalWidth += childSize.width();
maxUnderBaseline = max(maxUnderBaseline, childSize.height() - l->baseline());
maxAboveBaseline = max(maxAboveBaseline, l->baseline());
}
m_frame.setSize(KDSize(totalWidth, maxUnderBaseline + maxAboveBaseline));
m_sized = true;
}
void HorizontalLayoutNode::computeBaseline() {
assert(!m_baselined);
m_baseline = 0;
for (LayoutNode * l : directChildren()) {
m_baseline = max(m_baseline, l->baseline());
}
m_baselined = true;
}
KDPoint HorizontalLayoutNode::positionOfChild(LayoutNode * l) {
assert(hasChild(l));
KDCoordinate x = 0;
int index = indexOfChild(l);
assert(index > -1);
if (index > 0) {
LayoutNode * previousChild = child(index-1);
x = previousChild->origin().x() + previousChild->size().width();
}
KDCoordinate y = baseline() - l->baseline();
return KDPoint(x, y);
}
}

View File

@@ -14,8 +14,8 @@ bool LayoutCursor::isEquivalentTo(LayoutCursor cursor) {
/* Position */
int LayoutCursor::middleLeftPoint() {
int layoutOrigin = layoutReference().absoluteOrigin();
KDPoint LayoutCursor::middleLeftPoint() {
KDPoint layoutOrigin = layoutReference().absoluteOrigin();
return layoutOrigin;
}

View File

@@ -4,39 +4,65 @@
namespace Poincare {
TreeNode * LayoutNode::FailedAllocationStaticNode() {
return LayoutRef::FailedAllocationStaticNode();
}
// Rendering
void LayoutNode::draw() {
for (LayoutNode * child : children()) {
child->draw();
void LayoutNode::draw(KDContext * ctx, KDPoint p, KDColor expressionColor, KDColor backgroundColor) {
for (LayoutNode * l : children()) {
l->draw(ctx, p, expressionColor, backgroundColor);
}
render();
render(ctx, absoluteOrigin().translatedBy(p), expressionColor, backgroundColor);
}
int LayoutNode::origin() {
LayoutNode * parentLayout = parent();
if (parentLayout == nullptr) {
KDPoint LayoutNode::origin() {
LayoutNode * p = parent();
if (p != nullptr) {
return absoluteOrigin();
} else {
return 1; //KDPoint(absoluteOrigin().x() - parentLayout->absoluteOrigin().x(), absoluteOrigin().y() - parentLayout->absoluteOrigin().y());
return KDPoint(absoluteOrigin().x() - p->absoluteOrigin().x(),
absoluteOrigin().y() - p->absoluteOrigin().y());
}
return 0;
}
int LayoutNode::absoluteOrigin() {
/*if (!m_positioned) {
LayoutNode * parentLayout = parent();
if (parentLayout != nullptr) {
m_frame.setOrigin(parentLayout->absoluteOrigin().translatedBy(parentLayout->positionOfChild(this)));
KDPoint LayoutNode::absoluteOrigin() {
LayoutNode * p = parent();
if (!m_positioned) {
if (p != nullptr) {
m_frame.setOrigin(p->absoluteOrigin().translatedBy(p->positionOfChild(this)));
} else {
m_frame.setOrigin(KDPointZero);
}
m_positioned = true;
}
return m_frame.origin();*/
return 1;
return m_frame.origin();
}
KDSize LayoutNode::layoutSize() {
if (!m_sized) {
computeSize();
}
return m_frame.size();
}
KDCoordinate LayoutNode::baseline() {
if (!m_baselined) {
computeBaseline();
}
return m_baseline;
}
void LayoutNode::invalidAllSizesPositionsAndBaselines() {
m_sized = false;
m_positioned = false;
m_baselined = false;
for (LayoutNode * l : children()) {
l->invalidAllSizesPositionsAndBaselines();
}
}
// TreeNode
TreeNode * LayoutNode::FailedAllocationStaticNode() {
return LayoutRef::FailedAllocationStaticNode();
}
}