Calculuaⁿ Code
A downloadable project
Source Code:
#!/usr/bin/env python3
"""
Calculuaⁿ (Alpha 0.6)
Features include:
- A full-screen analysis panel with a horizontal scrollable category bar
- Inverse trigonometric helpers for degrees and statistics functions
- A settings popup for angle mode, UI theme, and decimal places
- A plugins screen and multiple splash texts
"""
import random
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.core.window import Window
from kivy.graphics import Color, Rectangle
from kivy.clock import Clock
from kivy.animation import Animation
from kivy.core.clipboard import Clipboard
from sympy import (sympify, sqrt, Eq, solve, sin, cos, tan, asin, acos, atan,
pi, SympifyError, Basic, hyper, Si, Ci, factorial)
from sympy.combinatorics import SymmetricGroup, AlternatingGroup, CyclicGroup, DihedralGroup
from sympy.combinatorics.free_groups import free_group
from sympy.combinatorics.perm_groups import PermutationGroup
# (Removed get_step_by_step since step-by-step solutions are no longer needed)
class FallingEquations(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.equations = [
"E = mc²", "a² + b² = c²", "∫f(x)dx", "π ≈ 3.14",
"sin(x) = x", "x² + y² = z²", "d/dx (x²) = 2x",
"1 + x = x + 1", "3 - 2 = 1", "a + bi", "0", "1", "2",
"3", "4", "5", "6", "7", "8", "9", "10"
]
Clock.schedule_interval(self.spawn_equation, 1.0)
def spawn_equation(self, dt):
eq_text = random.choice(self.equations)
eq_label = Label(text=eq_text, font_size='20sp', color=(1, 1, 1, 0.3))
eq_label.texture_update()
label_width = eq_label.texture_size[0]
start_x = random.uniform(0, max(Window.width - label_width, 0))
eq_label.pos = (start_x, self.height)
self.add_widget(eq_label)
duration = random.uniform(4, 8)
anim = Animation(y=-eq_label.texture_size[1], duration=duration)
anim.bind(on_complete=lambda a, widget: self.remove_widget(widget))
anim.start(eq_label)
class TitleScreenLayout(FloatLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas.before:
Color(0, 0, 0, 1)
self.rect = Rectangle(pos=self.pos, size=Window.size)
self.bind(size=self.update_rect, pos=self.update_rect)
self.add_widget(FallingEquations())
top_box = BoxLayout(orientation='vertical', size_hint=(0.8, 0.25),
pos_hint={'center_x': 0.5, 'top': 0.95}, spacing=10)
self.add_widget(top_box)
logo = Label(text="[b]Calculuaⁿ[/b]", markup=True, font_size='64sp',
color=(1, 1, 1, 1), size_hint=(1, None))
logo.texture_update(); logo.height = logo.texture_size[1]
top_box.add_widget(logo)
splash = Label(text=random.choice([
"Crunch numbers and decode algebra!",
"Plug in, solve, and celebrate!",
"Get ready to compute your world!",
"Malcolm, this might be for you.",
"Symbolab who?",
"Who reads these?",
"Goldmine of mathematics...",
"Beware of abstract algebra..."
]), font_size='20sp', color=(1, 1, 1, 1), size_hint=(1, None))
splash.texture_update(); splash.height = splash.texture_size[1]
top_box.add_widget(splash)
btn_layout = BoxLayout(orientation='vertical', size_hint=(0.6, 0.3),
pos_hint={'center_x': 0.5, 'y': 0.1}, spacing=20)
start_btn = Button(text="Start Calculating", font_size='24sp',
background_color=(0.1, 0.1, 0.3, 1), color=(1, 1, 1, 1))
start_btn.bind(on_press=lambda inst: setattr(App.get_running_app().root, 'current', 'calc'))
plugins_btn = Button(text="Plugins", font_size='24sp',
background_color=(0.1, 0.1, 0.3, 1), color=(1, 1, 1, 1))
plugins_btn.bind(on_press=lambda inst: setattr(App.get_running_app().root, 'current', 'plugins'))
exit_btn = Button(text="Exit", font_size='24sp',
background_color=(0.5, 0, 0, 1), color=(1, 1, 1, 1))
exit_btn.bind(on_press=lambda _: App.get_running_app().stop())
btn_layout.add_widget(start_btn)
btn_layout.add_widget(plugins_btn)
btn_layout.add_widget(exit_btn)
self.add_widget(btn_layout)
def update_rect(self, *args):
self.rect.pos = self.pos; self.rect.size = self.size
class PluginsScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.name = "plugins"
layout = BoxLayout(orientation='vertical', padding=20, spacing=20)
layout.add_widget(Label(text="[b]Plugins[/b]\n\nPlugins coming soon!", markup=True, font_size='32sp'))
back_btn = Button(text="Back", size_hint=(1, 0.2), font_size='24sp',
background_color=(0.1, 0.1, 0.3, 1), color=(1, 1, 1, 1))
back_btn.bind(on_press=lambda inst: setattr(App.get_running_app().root, 'current', 'title'))
layout.add_widget(back_btn)
self.add_widget(layout)
class TitleScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.name = "title"
self.add_widget(TitleScreenLayout())
class CalculatorScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.name = "calc"
self.add_widget(Calculuan())
def mean_func(*vals):
from math import fsum
arr = [float(v.evalf()) for v in vals]
return fsum(arr) / len(arr)
def median_func(*vals):
arr = sorted([float(v.evalf()) for v in vals])
n = len(arr)
return arr[n // 2] if n % 2 == 1 else (arr[n // 2 - 1] + arr[n // 2]) / 2
def mode_func(*vals):
from collections import Counter
arr = [float(v.evalf()) for v in vals]
c = Counter(arr); max_count = max(c.values())
for k in c:
if c[k] == max_count:
return k
def stdev_func(*vals):
import math
arr = [float(v.evalf()) for v in vals]; n = len(arr)
m = sum(arr) / n; var = sum((x - m) ** 2 for x in arr) / n
return math.sqrt(var)
def variance_func(*vals):
arr = [float(v.evalf()) for v in vals]; n = len(arr)
m = sum(arr) / n; return sum((x - m) ** 2 for x in arr) / n
def sin_deg(x): return sin(x * pi / 180)
def cos_deg(x): return cos(x * pi / 180)
def tan_deg(x): return tan(x * pi / 180)
def asin_deg(x): return asin(x) * 180 / pi
def acos_deg(x): return acos(x) * 180 / pi
def atan_deg(x): return atan(x) * 180 / pi
def approximate_result(res, digits=5):
if isinstance(res, dict):
return {str(k): approximate_result(v, digits) for k, v in res.items()}
elif isinstance(res, (list, tuple)):
return [approximate_result(x, digits) for x in res]
elif isinstance(res, Basic):
try:
return f"{float(res.evalf(digits + 2)):.{digits}f}"
except:
return str(res)
elif isinstance(res, float):
return f"{res:.{digits}f}"
return res
class Calculuan(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.orientation = 'vertical'; self.padding = 20; self.spacing = 15
self.angle_mode = "radians"; self.current_theme = "Blue"; self.decimal_places = 5
self.ui_themes = {
"Red": (0.5, 0, 0, 1), "Green": (0, 0.5, 0, 1),
"Blue": (0, 0, 0.5, 1), "Purple": (0.4, 0, 0.4, 1),
"Pink": (1, 0.4, 0.6, 1), "Orange": (1, 0.5, 0, 1),
"Yellow": (1, 1, 0, 1), "Gray": (0.5, 0.5, 0.5, 1),
"Black": (0, 0, 0, 1)
}
Window.clearcolor = self.ui_themes[self.current_theme]
with self.canvas.before:
Color(*self.ui_themes[self.current_theme])
self.rect = Rectangle(pos=self.pos, size=self.size)
self.bind(pos=self.update_rect, size=self.update_rect)
top_bar = BoxLayout(orientation='horizontal', size_hint=(1, 0.2))
self.title_label = Label(text="[b]Welcome to Calculuaⁿ![/b]\n[i]Enter an expression.[/i]",
halign='left', markup=True, font_size='20sp', color=(1, 1, 1, 1))
top_bar.add_widget(self.title_label)
settings_btn = Button(text="Settings", size_hint=(0.2, 1), font_size='24sp',
background_color=(0.1, 0.1, 0.3, 1), color=(1, 1, 1, 1))
settings_btn.bind(on_press=self.open_settings)
top_bar.add_widget(settings_btn)
self.add_widget(top_bar)
self.input_expr = TextInput(multiline=False, hint_text="Enter expression here",
size_hint=(1, 0.15), background_color=(0.2, 0.2, 0.2, 1),
foreground_color=(1, 1, 1, 1), padding=[10, 10, 10, 10], font_size='18sp')
self.add_widget(self.input_expr)
category_scroll = ScrollView(size_hint=(1, 0.15), do_scroll_x=True, do_scroll_y=False)
self.category_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint=(None, 1))
self.category_layout.bind(minimum_width=self.category_layout.setter('width'))
category_scroll.add_widget(self.category_layout)
self.add_widget(category_scroll)
self.categories = [
"Arithmetic", "Functions", "Trigonometry", "Calculus",
"Special Functions", "Complex", "Number Theory", "Linear Algebra",
"Statistics", "Abstract Algebra", "Set Theory"
]
self.keyboard_categories = {
"Arithmetic": [["7", "8", "9", "/", "("],
["4", "5", "6", "*", ")"],
["1", "2", "3", "-", "Del"],
["0", ".", "+", "Clear", ","]],
"Functions": [["sqrt(", "**", "x", "log(", "exp("],
["abs(", "factor(", "=", "pi", "E"]],
"Trigonometry": [["sin(", "cos(", "tan(", "asin(", "acos("],
["atan(", "", "", "", ""]],
"Calculus": [["integrate(", "diff(", "limit(", "summation(", "product("]],
"Special Functions": [["gamma(", "zeta(", "erf(", "LambertW(", "factorial("],
["Si(", "Ci(", "hyper(", "", ""]],
"Complex": [["I", "conjugate(", "re(", "im(", ""],
["", "", "", "", ""]],
"Number Theory": [["gcd(", "lcm(", "isprime(", "nextprime(", ""],
["factorint(", "divisors(", "", "", ""]],
"Linear Algebra": [["Matrix(", "det(", "DefineMatrix", "", ""]],
"Statistics": [["mean(", "median(", "mode(", "stdev(", "variance("],
["", "", "", "", ""]],
"Abstract Algebra": [["SymmetricGroup(", "AlternatingGroup(", "CyclicGroup(", "DihedralGroup(", "FreeGroup("]],
"Set Theory": [["Union(", "Intersection(", "SetDiff(", "SymDiff(", "{}"],
["EmptySet", "Subset(", "Superset(", "Complement(", ""]]
}
for cat in self.categories:
btn = Button(text=cat, size_hint=(None, 1), width=180, font_size=16,
halign='center', valign='middle', background_color=(0.1, 0.1, 0.3, 1),
color=(1, 1, 1, 1))
btn.bind(on_press=lambda inst, c=cat: self.switch_keyboard(c))
self.category_layout.add_widget(btn)
self.keyboard_container = BoxLayout(size_hint=(1, 0.35))
self.add_widget(self.keyboard_container)
self.current_category = "Arithmetic"
self.current_keyboard = self.build_keyboard_grid(self.current_category)
self.keyboard_container.add_widget(self.current_keyboard)
self.compute_btn = Button(text="Compute", size_hint=(1, 0.2),
background_color=(0.1, 0.1, 0.3, 1), color=(1, 1, 1, 1),
font_size='18sp')
self.compute_btn.bind(on_press=self.evaluate)
self.add_widget(self.compute_btn)
version_box = FloatLayout(size_hint=(1, 0.05))
self.add_widget(version_box)
self.version_label = Label(text="Alpha 0.6", size_hint=(None, None),
pos_hint={"right": 1, "bottom": 1},
color=(1, 1, 1, 0.7), font_size='14sp')
version_box.add_widget(self.version_label)
def update_rect(self, *args):
self.rect.pos = self.pos; self.rect.size = self.size
def build_keyboard_grid(self, category):
grid = GridLayout(cols=5, spacing=5)
for row in self.keyboard_categories.get(category, []):
for key in row:
if key == "":
grid.add_widget(Label(text=""))
else:
btn = Button(text=key, background_color=(0.1, 0.1, 0.3, 1),
color=(1, 1, 1, 1), font_size='16sp')
btn.bind(on_press=self.on_key_press)
grid.add_widget(btn)
return grid
def switch_keyboard(self, category):
self.current_category = category
self.keyboard_container.clear_widgets()
self.keyboard_container.add_widget(self.build_keyboard_grid(category))
def on_key_press(self, instance):
key = instance.text
if key == "DefineMatrix":
self.open_matrix_popup()
return
if key == "Del":
self.input_expr.text = self.input_expr.text[:-1]
elif key == "Clear":
self.input_expr.text = ""
else:
self.input_expr.text += key
def open_matrix_popup(self):
layout = BoxLayout(orientation='vertical', spacing=10, padding=10)
row_box = BoxLayout(orientation='horizontal', spacing=10)
row_box.add_widget(Label(text="Rows:", size_hint=(0.4, 1)))
row_input = TextInput(text="2", multiline=False, size_hint=(0.6, 1), input_filter='int')
row_box.add_widget(row_input)
col_box = BoxLayout(orientation='horizontal', spacing=10)
col_box.add_widget(Label(text="Columns:", size_hint=(0.4, 1)))
col_input = TextInput(text="2", multiline=False, size_hint=(0.6, 1), input_filter='int')
col_box.add_widget(col_input)
layout.add_widget(row_box); layout.add_widget(col_box)
btn_box = BoxLayout(orientation='horizontal', spacing=10, size_hint=(1, 0.3))
ok_btn = Button(text="OK", background_color=(0.1, 0.5, 0.1, 1), color=(1, 1, 1, 1))
cancel_btn = Button(text="Cancel", background_color=(0.5, 0.1, 0.1, 1), color=(1, 1, 1, 1))
btn_box.add_widget(ok_btn); btn_box.add_widget(cancel_btn); layout.add_widget(btn_box)
matrix_popup = Popup(title="Define Matrix Size", content=layout, size_hint=(0.8, 0.4))
def on_ok(_):
try:
rows = int(row_input.text); cols = int(col_input.text)
if rows < 1 or cols < 1:
raise ValueError("Rows and columns must be >= 1.")
if rows > 7 or cols > 7:
raise ValueError("Max 7 rows or columns allowed.")
matrix_str = "Matrix([" + ",".join([f"[{','.join(['0']*cols)}]" for _ in range(rows)]) + "])"
self.input_expr.text += matrix_str; matrix_popup.dismiss()
except Exception as e:
self.input_expr.text += f" # Error: {e}"; matrix_popup.dismiss()
ok_btn.bind(on_press=on_ok); cancel_btn.bind(on_press=lambda _: matrix_popup.dismiss())
matrix_popup.open()
def open_settings(self, _):
content = BoxLayout(orientation='vertical', spacing=10, padding=10)
mode_bar = BoxLayout(orientation='horizontal', spacing=10)
degrees_btn = Button(text="Degrees", font_size='16sp', background_color=(0.2,0.2,0.2,1), color=(1,1,1,1))
radians_btn = Button(text="Radians", font_size='16sp', background_color=(0.2,0.2,0.2,1), color=(1,1,1,1))
def set_degrees(_): self.angle_mode = "degrees"; degrees_btn.background_color = (0.1,0.6,0.1,1); radians_btn.background_color = (0.2,0.2,0.2,1)
def set_radians(_): self.angle_mode = "radians"; radians_btn.background_color = (0.1,0.6,0.1,1); degrees_btn.background_color = (0.2,0.2,0.2,1)
if self.angle_mode == "degrees":
degrees_btn.background_color = (0.1,0.6,0.1,1)
else:
radians_btn.background_color = (0.1,0.6,0.1,1)
degrees_btn.bind(on_press=set_degrees); radians_btn.bind(on_press=set_radians)
mode_bar.add_widget(degrees_btn); mode_bar.add_widget(radians_btn)
theme_bar = BoxLayout(orientation='horizontal', spacing=10)
for theme in self.ui_themes.keys():
btn = Button(text=theme, font_size='16sp', background_color=(0.2,0.2,0.2,1), color=(1,1,1,1))
def on_theme_press(btn_inst, theme=theme):
self.current_theme = theme; self.update_theme()
for child in theme_bar.children:
child.background_color = (0.2,0.2,0.2,1)
btn_inst.background_color = (0.1,0.6,0.1,1)
if theme == self.current_theme:
btn.background_color = (0.1,0.6,0.1,1)
btn.bind(on_press=on_theme_press); theme_bar.add_widget(btn)
decimal_box = BoxLayout(orientation='horizontal', spacing=10)
decimal_box.add_widget(Label(text="Decimal Places:", font_size='18sp', color=(1,1,1,1)))
decimal_input = TextInput(text=str(self.decimal_places), multiline=False,
size_hint=(0.3,1), input_filter='int',
background_color=(0.2,0.2,0.2,1), foreground_color=(1,1,1,1))
apply_btn = Button(text="Apply", font_size='16sp',
background_color=(0.1,0.3,0.1,1), color=(1,1,1,1),
size_hint=(0.3,1))
def apply_settings(_):
try:
val = int(decimal_input.text)
if val < 1 or val > 15:
raise ValueError("Decimal places must be 1..15")
self.decimal_places = val
except Exception as e:
decimal_input.text = str(self.decimal_places)
apply_btn.bind(on_press=apply_settings)
decimal_box.add_widget(decimal_input); decimal_box.add_widget(apply_btn)
content.add_widget(mode_bar); content.add_widget(theme_bar); content.add_widget(decimal_box)
Popup(title="Settings", content=content, size_hint=(0.9,0.7)).open()
def update_theme(self):
new_color = self.ui_themes[self.current_theme]
Window.clearcolor = new_color; self.canvas.before.clear()
with self.canvas.before:
Color(*new_color); self.rect = Rectangle(pos=self.pos, size=self.size)
def evaluate_expression(self, expr):
from sympy import Eq, solve
try:
trig_locals = {"sin": sin_deg, "cos": cos_deg, "tan": tan_deg} if self.angle_mode=="degrees" else {"sin": sin, "cos": cos, "tan": tan}
stats_locals = {"mean": mean_func, "median": median_func, "mode": mode_func, "stdev": stdev_func, "variance": variance_func}
base_locals = {"sqrt": sqrt, "pi": pi, "Si": Si, "Ci": Ci, "hyper": hyper, "factorial": factorial,
"SymmetricGroup": SymmetricGroup, "AlternatingGroup": AlternatingGroup,
"CyclicGroup": CyclicGroup, "DihedralGroup": DihedralGroup, "FreeGroup": free_group}
locals_dict = {}; locals_dict.update(base_locals); locals_dict.update(trig_locals); locals_dict.update(stats_locals)
if '=' in expr:
parts = expr.split('=')
if len(parts) != 2:
return "Error: Equation must have exactly one '=' sign."
left_expr = sympify(parts[0].strip(), locals=locals_dict)
right_expr = sympify(parts[1].strip(), locals=locals_dict)
symbols = list(left_expr.free_symbols.union(right_expr.free_symbols))
raw_result = solve(Eq(left_expr, right_expr), symbols) if symbols else (left_expr == right_expr)
else:
raw_result = sympify(expr, locals=locals_dict)
disp_result = approximate_result(raw_result, self.decimal_places) if not isinstance(raw_result, PermutationGroup) else raw_result
return (raw_result, disp_result)
except ZeroDivisionError as e:
return f"Division by zero error: {e}"
except SympifyError as e:
return f"Error parsing expression: {e}"
except Exception as e:
return f"An error occurred: {e}"
def open_analysis_panel(self, expr, eval_result):
from sympy import Eq, solve
if isinstance(eval_result, tuple):
raw_result, disp_result = eval_result
else:
raw_result = eval_result; disp_result = approximate_result(eval_result, self.decimal_places)
locals_dict = {"sin": sin_deg, "cos": cos_deg, "tan": tan_deg} if self.angle_mode=="degrees" else {"sin": sin, "cos": cos, "tan": tan}
locals_dict.update({"sqrt": sqrt, "pi": pi, "Si": Si, "Ci": Ci, "hyper": hyper, "factorial": factorial,
"SymmetricGroup": SymmetricGroup, "AlternatingGroup": AlternatingGroup,
"CyclicGroup": CyclicGroup, "DihedralGroup": DihedralGroup, "FreeGroup": free_group})
try:
base_expr = sympify(expr, locals=locals_dict)
except Exception:
base_expr = expr
analysis_items = [("Original Expression", str(expr)), ("Evaluated Result", str(disp_result))]
if hasattr(base_expr, "free_symbols") and base_expr.free_symbols:
for method, label in [(lambda e: e.simplify(), "Simplified"),
(lambda e: e.expand(), "Expanded"),
(lambda e: e.factor(), "Factorized"),
(lambda e: e.diff(), "Derivative"),
(lambda e: e.integrate(), "Integral")]:
try:
analysis_items.append((label, str(method(base_expr))))
except Exception as e:
analysis_items.append((label, f"Error: {e}"))
if '=' in expr:
try:
parts = expr.split('=')
left_expr = sympify(parts[0].strip(), locals=locals_dict)
right_expr = sympify(parts[1].strip(), locals=locals_dict)
sol = solve(Eq(left_expr, right_expr))
analysis_items.append(("Roots", str(approximate_result(sol, self.decimal_places))))
except Exception as e:
analysis_items.append(("Roots", f"Error: {e}"))
group_keywords = ["SymmetricGroup(", "AlternatingGroup(", "CyclicGroup(", "DihedralGroup(", "FreeGroup("]
if any(keyword in expr for keyword in group_keywords):
if isinstance(raw_result, PermutationGroup):
for label, method in [("Group Order", lambda g: g.order()),
("Group Degree", lambda g: g.degree),
("Group Generators", lambda g: ", ".join(str(gen) for gen in g.generators))]:
try:
analysis_items.append((label, str(method(raw_result))))
except Exception as e:
analysis_items.append((label, f"Error: {e}"))
else:
analysis_items.append(("Abstract Algebra Info", "Result in concrete permutation representation."))
analysis_layout = BoxLayout(orientation='vertical', spacing=10, padding=10)
panel_top = BoxLayout(orientation='horizontal', size_hint=(1, 0.1))
panel_title = Label(text="[b]Analysis Panel[/b]", markup=True, font_size='24sp',
color=(1,1,1,1), size_hint=(0.6,1))
copy_btn = Button(text="Copy", size_hint=(0.2, 1), font_size='24sp',
background_color=(0.2,0.2,0.2,1), color=(1,1,1,1))
close_btn = Button(text="X", size_hint=(0.2, 1), font_size='24sp',
background_color=(1,0,0,1), color=(1,1,1,1))
panel_top.add_widget(panel_title); panel_top.add_widget(copy_btn); panel_top.add_widget(close_btn)
analysis_layout.add_widget(panel_top)
def copy_analysis(_):
Clipboard.copy("\n".join(f"{title}: {content}" for title, content in analysis_items))
copy_btn.bind(on_press=copy_analysis)
scroll = ScrollView(size_hint=(1, 0.9))
details_layout = BoxLayout(orientation='vertical', spacing=10, size_hint_y=None, padding=10)
details_layout.bind(minimum_height=details_layout.setter('height'))
for title, content in analysis_items:
if content and content != "None":
lbl = Label(text=f"[b]{title}:[/b] {content}", markup=True,
font_size='24sp', color=(1,1,1,1), halign='left', valign='top', size_hint_y=None)
lbl.bind(texture_size=lbl.setter('size')); lbl.text_size = (Window.width * 0.9, None)
details_layout.add_widget(lbl)
scroll.add_widget(details_layout); analysis_layout.add_widget(scroll)
panel_popup = Popup(title="", content=analysis_layout, size_hint=(1,1))
panel_popup.background = ""; panel_popup.background_color = (0,0,0.8,1)
close_btn.bind(on_press=lambda _: panel_popup.dismiss()); panel_popup.open()
def evaluate(self, _):
user_expr = self.input_expr.text
if user_expr.lower() in ['quit', 'exit']:
App.get_running_app().stop()
result = self.evaluate_expression(user_expr)
self.open_analysis_panel(user_expr, result)
class CalculuanApp(App):
def build(self):
Window.title = "Calculuaⁿ"
sm = ScreenManager(transition=FadeTransition())
sm.add_widget(TitleScreen())
sm.add_widget(CalculatorScreen())
sm.add_widget(PluginsScreen())
sm.current = "title"
return sm
if __name__ == '__main__':
CalculuanApp().run()
Status | In development |
Category | Other |
Author | JackCraftSolar |
Tags | AI Generated, calculator, calculua, Math, tech, tools |
Leave a comment
Log in with itch.io to leave a comment.