Commit b0d07eb8 authored by Rohan Asokan's avatar Rohan Asokan
Browse files
parents 710381b8 cf60acbe
......@@ -51,3 +51,6 @@ prime/
stage/
*.snap
*source.tar.bz2
# Clang
.clang-format
......@@ -641,7 +641,10 @@ QString KNumber::toBinaryString(int precision) const
{
return value_->toBinaryString(precision);
}
QString KNumber::toHexString(int precision) const
{
return value_->toHexString(precision);
}
//------------------------------------------------------------------------------
// Name: toUint64
//------------------------------------------------------------------------------
......
......@@ -109,8 +109,9 @@ public:
KNumber integerPart() const;
public:
QString toQString(int width = -1, int precision = -1) const;
QString toQString(int width = 16, int precision = -1) const;
QString toBinaryString(int precision) const;
QString toHexString(int precision) const;
quint64 toUint64() const;
qint64 toInt64() const;
......
......@@ -43,6 +43,7 @@ public:
public:
virtual QString toString(int precision) const = 0;
virtual QString toBinaryString(int precision) const = 0;
virtual QString toHexString(int precision) const = 0;
virtual quint64 toUint64() const = 0;
virtual qint64 toInt64() const = 0;
......
......@@ -112,6 +112,19 @@ QString knumber_error::toBinaryString(int precision) const {
return QStringLiteral("nan");
}
}
QString knumber_error::toHexString(int precision) const {
Q_UNUSED(precision);
switch(error_) {
case ERROR_POS_INFINITY:
return QStringLiteral("inf");
case ERROR_NEG_INFINITY:
return QStringLiteral("-inf");
case ERROR_UNDEFINED:
default:
return QStringLiteral("nan");
}
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
......
......@@ -47,6 +47,7 @@ public:
public:
QString toString(int precision) const override;
QString toBinaryString(int precision) const override;
QString toHexString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
......
......@@ -612,6 +612,25 @@ QString knumber_float::toBinaryString(int precision) const {
return QLatin1String(&buf[0]);
}
QString knumber_float::toHexString(int precision) const {
size_t size;
if (precision > 0) {
size = static_cast<size_t>(mpfr_snprintf(nullptr, 0, "%.*Rh", precision, mpfr_) + 1);
} else {
size = static_cast<size_t>(mpfr_snprintf(nullptr, 0, "%.Rh", mpfr_) + 1);
}
QScopedArrayPointer<char> buf(new char[size]);
if (precision > 0) {
mpfr_snprintf(&buf[0], size, "%.*Rh", precision, mpfr_);
} else {
mpfr_snprintf(&buf[0], size, "%.Rh", mpfr_);
}
return QLatin1String(&buf[0]);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
......
......@@ -56,6 +56,7 @@ private:
public:
QString toString(int precision) const override;
QString toBinaryString(int precision) const override;
QString toHexString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
......
......@@ -825,6 +825,52 @@ QString knumber_fraction::toBinaryString(int precision) const {
return knumber_float(this).toString(precision);
}
}
QString knumber_fraction::toHexString(int precision) const {
if(knumber_fraction::default_fractional_output) {
// TODO: figure out how to properly use mpq_numref/mpq_denref here
knumber_integer integer_part(this);
if(split_off_integer_for_fraction_output && !integer_part.is_zero()) {
mpz_t num;
mpz_init(num);
mpq_get_num(num, mpq_);
knumber_integer integer_part_1(this);
mpz_mul(integer_part.mpz_, integer_part.mpz_, mpq_denref(mpq_));
mpz_sub(num, num, integer_part.mpz_);
if(mpz_sgn(num) < 0) {
mpz_neg(num, num);
}
const size_t size = gmp_snprintf(nullptr, 0, "%Zh %Zh/%Zh", integer_part_1.mpz_, num, mpq_denref(mpq_)) + 1;
QScopedArrayPointer<char> buf(new char[size]);
gmp_snprintf(&buf[0], size, "%Zh %Zh/%Zh", integer_part_1.mpz_, num, mpq_denref(mpq_));
mpz_clear(num);
return QLatin1String(&buf[0]);
} else {
mpz_t num;
mpz_init(num);
mpq_get_num(num, mpq_);
const size_t size = gmp_snprintf(nullptr, 0, "%Zh/%Zh", num, mpq_denref(mpq_)) + 1;
QScopedArrayPointer<char> buf(new char[size]);
gmp_snprintf(&buf[0], size, "%Zh/%Zh", num, mpq_denref(mpq_));
mpz_clear(num);
return QLatin1String(&buf[0]);
}
} else {
return knumber_float(this).toString(precision);
}
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
......
......@@ -54,6 +54,7 @@ public:
public:
QString toString(int precision) const override;
QString toBinaryString(int precision) const override;
QString toHexString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
......
......@@ -721,6 +721,10 @@ QString knumber_integer::toBinaryString(int precision) const
Q_UNUSED(precision);
return QString::fromLatin1(mpz_get_str(NULL, 2, mpz_));
}
QString knumber_integer::toHexString(int precision) const {
Q_UNUSED(precision);
return QString::fromLatin1(mpz_get_str(NULL, 16, mpz_));
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
......
......@@ -47,6 +47,7 @@ public:
public:
QString toString(int precision) const override;
QString toBinaryString(int precision) const override;
QString toHexString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
......
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan
* <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "inputmanager.h"
#include "mathengine.h"
#include "historymanager.h"
#include "mathengine.h"
#include <QDebug>
InputManager::InputManager()
{
......@@ -35,10 +36,8 @@ const QString &InputManager::result() const
void InputManager::append(const QString &subexpression)
{
// if expression was from result and input is numeric, clear expression
if(m_moveFromResult && subexpression.size() == 1)
{
if(subexpression.at(0).isDigit() || subexpression.at(0) == QLatin1Char('.'))
{
if (m_moveFromResult && subexpression.size() == 1) {
if (subexpression.at(0).isDigit() || subexpression.at(0) == QLatin1Char('.')) {
m_expression.clear();
m_stack.pop_back();
}
......@@ -46,15 +45,14 @@ void InputManager::append(const QString &subexpression)
m_moveFromResult = false;
// Call the corresponding parser based on the type of expression.
MathEngine * engineInstance = MathEngine::inst();
MathEngine *engineInstance = MathEngine::inst();
if (m_isBinaryMode) {
engineInstance->parseBinaryExpression(m_expression + subexpression);
} else {
engineInstance->parse(m_expression + subexpression);
}
if(!MathEngine::inst()->error())
{
if (!MathEngine::inst()->error()) {
m_stack.push_back(subexpression.size());
m_result = MathEngine::inst()->result();
m_expression += subexpression;
......@@ -65,21 +63,19 @@ void InputManager::append(const QString &subexpression)
void InputManager::backspace()
{
if(!m_stack.empty())
{
if (!m_stack.empty()) {
m_expression.chop(m_stack.back());
Q_EMIT expressionChanged();
// Call the corresponding parser based on the type of expression.
MathEngine * engineInstance = MathEngine::inst();
MathEngine *engineInstance = MathEngine::inst();
if (m_isBinaryMode) {
engineInstance->parseBinaryExpression(m_expression);
} else {
engineInstance->parse(m_expression);
}
if(!MathEngine::inst()->error())
{
if (!MathEngine::inst()->error()) {
m_result = MathEngine::inst()->result();
Q_EMIT resultChanged();
}
......@@ -110,7 +106,7 @@ void InputManager::clear()
void InputManager::fromHistory(const QString &result)
{
m_expression = result;
setExpression(result);
m_result.clear();
m_stack.clear();
m_stack.push_back(result.size());
......@@ -119,8 +115,12 @@ void InputManager::fromHistory(const QString &result)
Q_EMIT expressionChanged();
Q_EMIT resultChanged();
}
void InputManager::setBinaryMode(bool active) {
bool InputManager::binaryMode() const
{
return m_isBinaryMode;
}
void InputManager::setBinaryMode(bool active)
{
m_isBinaryMode = active;
clear();
}
......@@ -23,6 +23,7 @@ public:
Q_INVOKABLE void equal();
Q_INVOKABLE void clear();
Q_INVOKABLE void fromHistory(const QString &result);
Q_INVOKABLE bool binaryMode() const;
Q_INVOKABLE void setBinaryMode(bool active);
Q_SIGNALS:
void expressionChanged();
......
......@@ -7,6 +7,11 @@ import QtQuick 2.0
import org.kde.kirigami 2.13 as Kirigami
Kirigami.AboutPage {
id: aboutPage
property real mainOpacity: 1
property int yTranslate: 0
opacity: mainOpacity
visible: false
title: i18n("About")
aboutData: {
......
......@@ -17,6 +17,9 @@ Kirigami.Page {
rightPadding: 0
bottomPadding: 0
property int yTranslate: 0
property real mainOpacity: 1
property color dropShadowColor: Qt.darker(Kirigami.Theme.backgroundColor, 1.15)
property int keypadHeight: {
let rows = 6, columns = 5;
......@@ -60,7 +63,8 @@ Kirigami.Page {
}
onIsCurrentPageChanged: {
inputManager.setBinaryMode(true)
if (!inputManager.binaryMode())
inputManager.setBinaryMode(true);
}
background: Rectangle {
......@@ -70,118 +74,125 @@ Kirigami.Page {
anchors.fill: parent
}
// top panel drop shadow
RectangularGlow {
anchors.fill: topPanelBackground
anchors.topMargin: 1
glowRadius: 4
spread: 0.2
color: dropShadowColor
}
Rectangle {
id: topPanelBackground
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
color: Kirigami.Theme.backgroundColor
implicitHeight: outputScreen.height
}
ColumnLayout {
Item {
anchors.fill: parent
spacing: 0
opacity: mainOpacity
transform: Translate { y: yTranslate }
// top panel drop shadow
RectangularGlow {
anchors.fill: topPanelBackground
anchors.topMargin: 1
glowRadius: 4
spread: 0.2
color: dropShadowColor
}
Rectangle {
id: topPanelBackground
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
color: Kirigami.Theme.backgroundColor
implicitHeight: outputScreen.height
}
Item {
id: outputScreen
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: initialPage.height - initialPage.keypadHeight
ColumnLayout {
id: mainScreen
anchors.fill: parent
spacing: 0
Column {
id: outputColumn
anchors.fill: parent
anchors.margins: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.gridUnit
Item {
id: outputScreen
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: initialPage.height - initialPage.keypadHeight
Flickable {
anchors.right: parent.right
height: Kirigami.Units.gridUnit * 1.5
width: Math.min(parent.width, contentWidth)
contentHeight: expressionRow.height
contentWidth: expressionRow.width
flickableDirection: Flickable.HorizontalFlick
Controls.Label {
id: expressionRow
horizontalAlignment: Text.AlignRight
font.pointSize: Kirigami.Units.gridUnit
font.weight: Font.Light
text: inputManager.expression
color: Kirigami.Theme.disabledTextColor
}
onContentWidthChanged: {
if(contentWidth > width)
contentX = contentWidth - width;
}
}
Flickable {
anchors.right: parent.right
height: Kirigami.Units.gridUnit * 4
width: Math.min(parent.width, contentWidth)
contentHeight: result.height
contentWidth: result.width
flickableDirection: Flickable.HorizontalFlick
Controls.Label {
id: result
horizontalAlignment: Text.AlignRight
font.pointSize: Kirigami.Units.gridUnit * 2
font.weight: Font.Light
text: inputManager.result
NumberAnimation on opacity {
id: resultFadeInAnimation
from: 0.5
to: 1
duration: Kirigami.Units.shortDuration
Column {
id: outputColumn
anchors.fill: parent
anchors.margins: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.gridUnit
Flickable {
anchors.right: parent.right
height: Kirigami.Units.gridUnit * 1.5
width: Math.min(parent.width, contentWidth)
contentHeight: expressionRow.height
contentWidth: expressionRow.width
flickableDirection: Flickable.HorizontalFlick
Controls.Label {
id: expressionRow
horizontalAlignment: Text.AlignRight
font.pointSize: Kirigami.Units.gridUnit
font.weight: Font.Light
text: inputManager.expression
color: Kirigami.Theme.disabledTextColor
}
NumberAnimation on opacity {
id: resultFadeOutAnimation
from: 1
to: 0
duration: Kirigami.Units.shortDuration
onContentWidthChanged: {
if(contentWidth > width)
contentX = contentWidth - width;
}
}
Flickable {
anchors.right: parent.right
height: Kirigami.Units.gridUnit * 4
width: Math.min(parent.width, contentWidth)
contentHeight: result.height
contentWidth: result.width
flickableDirection: Flickable.HorizontalFlick
Controls.Label {
id: result
horizontalAlignment: Text.AlignRight
font.pointSize: Kirigami.Units.gridUnit * 2
font.weight: Font.Light
text: inputManager.result
NumberAnimation on opacity {
id: resultFadeInAnimation
from: 0.5
to: 1
duration: Kirigami.Units.shortDuration
}
NumberAnimation on opacity {
id: resultFadeOutAnimation
from: 1
to: 0
duration: Kirigami.Units.shortDuration
}
onTextChanged: resultFadeInAnimation.start()
onTextChanged: resultFadeInAnimation.start()
}
}
}
}
}
// Binary Input Pad
Item {
property string expression: ""
id: binaryInputPad
Layout.fillHeight: true
Layout.preferredWidth: initialPage.width
Layout.alignment: Qt.AlignLeft
BinaryPad {
id: binaryPad
anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing
// Uncomment next line for function overlay
// anchors.rightMargin: Kirigami.Units.gridUnit * 1.5
onPressed: {
if (text == "DEL") {
inputManager.backspace();
} else if (text == "=") {
inputManager.equal();
resultFadeOutAnimation.start();
} else {
inputManager.append(text, true);
// Binary Input Pad
Item {
property string expression: ""
id: binaryInputPad
Layout.fillHeight: true
Layout.preferredWidth: initialPage.width
Layout.alignment: Qt.AlignLeft
BinaryPad {
id: binaryPad
anchors.fill: parent
anchors.margins: Kirigami.Units.smallSpacing
// Uncomment next line for function overlay
// anchors.rightMargin: Kirigami.Units.gridUnit * 1.5
onPressed: {
if (text == "DEL") {
inputManager.backspace();
} else if (text == "=") {
inputManager.equal();
resultFadeOutAnimation.start();
} else {
inputManager.append(text, true);
}
}
onClear: inputManager.clear()
}
onClear: inputManager.clear()
}
}
}
......
<
......@@ -18,6 +18,9 @@ Kirigami.Page {
rightPadding: 0
bottomPadding: 0
property int yTranslate: 0
property real mainOpacity: 1
property color dropShadowColor: Qt.darker(Kirigami.Theme.backgroundColor, 1.15)
readonly property bool inPortrait: initialPage.width < initialPage.height
property int keypadHeight: {
......@@ -79,191 +82,206 @@ Kirigami.Page {
// Changes the current mode of the backend to non-binary
onIsCurrentPageChanged: {
inputManager.setBinaryMode(false)
if (inputManager.binaryMode())
inputManager.setBinaryMode(false);
}
background: Rectangle {
opacity: mainOpacity
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
color: Kirigami.Theme.backgroundColor
anchors.fill: parent
}
// top panel drop shadow
RectangularGlow {
anchors.fill: topPanelBackground
anchors.topMargin: 1
glowRadius: 4
spread: 0.2
color: dropShadowColor
}
Rectangle {
id: topPanelBackground
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
color: Kirigami.Theme.backgroundColor
implicitHeight: outputScreen.height
}
ColumnLayout {
Item {
anchors.fill: parent
spacing: 0
opacity: mainOpacity
transform: Translate { y: yTranslate }
Item {
id: outputScreen
z: 1
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: initialPage.height - initialPage.keypadHeight