The settings category should have only one column but currently has two adjust the layout accordingly. Python 3.12 code: import math
import re
from typing import Any, Union, Callable

from PySide6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLineEdit, QTextEdit, QScrollBar, QPushButton, QLabel, QFrame,
QGridLayout
)
from PySide6.QtGui import QFont
from PySide6.QtCore import Qt
-- Utility Functions --

def convert_angle(func: Callable[[float], float], x: float, use_degrees: bool) -> float:
"""Convert angle based on degree mode."""
return func(math.radians(x) if use_degrees else x)
-- Conversions Category --

def kilograms_to_pounds(kg: float) -> float:
"""Convert kilograms to pounds."""
return kg / 0.45359237

def pounds_to_kilograms(lb: float) -> float:
"""Convert pounds to kilograms."""
return lb * 0.45359237

def celsius_to_kelvin(c: float) -> float:
"""Convert Celsius to Kelvin."""
return c + 273.15

def kelvin_to_celsius(k: float) -> float:
"""Convert Kelvin to Celsius."""
return k - 273.15

def celsius_to_fahrenheit(c: float) -> float:
"""Convert Celsius to Fahrenheit."""
return c * 9/5 + 32

def fahrenheit_to_celsius(f: float) -> float:
"""Convert Fahrenheit to Celsius."""
return (f - 32) * 5/9
-- Text Category --

def capitalize_sentence(sentence: str) -> str:
"""Capitalize the first letter of each word in the sentence."""
return ' '.join(word.capitalize() for word in sentence.split())

def remove_duplicates(text: str) -> str:
"""Remove duplicate words and empty lines from a string."""
words = ' '.join(line.strip() for line in text.splitlines() if line.strip()).split()
return ' '.join(dict.fromkeys(words))
-- Processing --

def get_safe_globals(use_degrees: bool) -> dict:
"""Return a dictionary of safe globals for expression evaluation."""
trig_funcs = {'sin', 'cos', 'tan', 'asin', 'acos', 'atan'}
safe_globals = {
"sqrt": math.sqrt,
"log": math.log10,
"ln": math.log,
"pi": math.pi,
"e": math.e,
"lb": kilograms_to_pounds,
"kg": pounds_to_kilograms,
"C": kelvin_to_celsius,
"K": celsius_to_kelvin,
"F": celsius_to_fahrenheit,
"CF": fahrenheit_to_celsius,
"capitalize": capitalize_sentence,
"duplicates": remove_duplicates,
}
safe_globals.update({
func: (lambda f: (lambda x, f=f: convert_angle(getattr(math, f), x, use_degrees)))(func)
for func in trig_funcs.union({'asin', 'acos'})
})
return safe_globals

def preprocess_text_functions(expression: str) -> str:
"""Preprocess text functions to ensure proper quoting of arguments."""
def add_quotes(match):
func, args = match.groups()
return f'{func}("{args}")' if func in ['capitalize', 'duplicates'] else match.group(0)
return re.sub(r'\b(capitalize|duplicates)(([^)]+))', add_quotes, expression)

def validate_inverse_trig(expression: str, safe_globals: dict) -> Union[str, None]:
"""Validate inputs for inverse trigonometric functions."""
for func, arg in re.findall(r"(\b\w+\b)(([^)]+))", expression):
if func in ["asin", "acos"]:
try:
value = eval(arg, {"builtins": None}, safe_globals)
if abs(value) > 1:
return f"Error: {func}(x) is undefined for |x| > 1"
except Exception as e:
return f"Error: {e}"
return None

def safe_evaluate(expression: str, safe_globals: dict, use_e_notation: bool) -> Union[str, Any]:
"""Safely evaluate the expression and format the result."""
try:
result = eval(expression, {"builtins": None}, safe_globals)
if isinstance(result, float) and abs(result) < 1e-10:
result = 0.0
if isinstance(result, (int, float)):
if use_e_notation:
# Format using scientific notation with up to 2 decimal places
result = f"{result:.2e}"
else:
# Standard formatting with rounding
result = round(result, 2)
return result
except Exception as e:
return f"Error: {e}"

def evaluate_expression(expression: str, use_degrees: bool = False, use_e_notation: bool = False) -> Union[float, str]:
"""Safely evaluate a mathematical expression considering degree mode."""
safe_globals = get_safe_globals(use_degrees)
expression = expression.replace("^", "**")
expression = preprocess_text_functions(expression)
error = validate_inverse_trig(expression, safe_globals)
return error or safe_evaluate(expression, safe_globals, use_e_notation)
-- GUI --

class CalculatorGUI(QMainWindow):
"""PySide6-based Calculator with Degrees/Radians toggle and history."""

def __init__(self):
    super().__init__()
    self.use_degrees = False
    self.use_e_notation = False  # New state variable for E notation
    self.setup_window()
    self.create_widgets()
    self.layout_widgets()

def setup_window(self) -> None:
    """Configure the main application window."""
    self.setWindowTitle("Calculator")
    self.setGeometry(100, 100, 1280, 720)

def create_widgets(self) -> None:
    """Initialize all GUI components."""
    font = QFont()
    font.setPointSize(12)
    font.setFamily('Literata')
    
    self.entry = QLineEdit()
    self.entry.setFont(font)
    self.entry.returnPressed.connect(self.calculate)
    self.entry.setPlaceholderText('Enter expression')
    self.entry.setClearButtonEnabled(True)  # Enable the clear (delete) button
    
    self.history_text = QTextEdit()
    self.history_text.setFont(font)
    self.history_text.setReadOnly(True)
    
    self.scrollbar = QScrollBar(Qt.Vertical)
    self.history_text.setVerticalScrollBar(self.scrollbar)
    
    self.function_buttons = {
        "Functions": ["sqrt", "sin", "cos", "tan", "asin", "acos", "atan", "log", "ln"],
        "Conversions": ["lb", "kg", "K", "C", "F", "CF"],
        "Text": ["capitalize", "duplicates"],
        "Constants": ["pi", "e"],
        "Settings": []  # Settings buttons are handled separately
    }
    self.function_frame = QFrame()
    self.create_function_buttons(font)

def create_function_buttons(self, font: QFont) -> None:
    """Create buttons for inserting functions into the entry."""
    layout = QGridLayout()
    
    categories = [("Functions", 3), ("Conversions", 2), ("Text", 2), ("Constants", 2), ("Settings", 2)]  # Increased Settings span
    starting_col = 0

    for category, col_span in categories:
        label = QLabel(category)
        label.setFont(font)
        layout.addWidget(label, 0, starting_col, 1, col_span, Qt.AlignCenter)

        buttons = self.function_buttons.get(category, [])
        if category == "Functions":
            for i, func in enumerate(buttons):
                button = QPushButton(func)
                button.setFont(font)
                button.clicked.connect(lambda _, f=func: self.insert_function(f, False))
                layout.addWidget(button, (i // 3) + 1, starting_col + (i % 3))
        
        elif category == "Settings":
            # Existing Mode Button
            self.mode_button = QPushButton("Radians")
            self.mode_button.setFont(font)
            self.mode_button.clicked.connect(self.toggle_mode)
            layout.addWidget(self.mode_button, 1, starting_col, 1, 1)
            
            # New E Notation Button
            self.e_notation_button = QPushButton("E Notation: Off")
            self.e_notation_button.setFont(font)
            self.e_notation_button.clicked.connect(self.toggle_e_notation)
            layout.addWidget(self.e_notation_button, 1, starting_col + 1, 1, 1)
        
        elif category == "Conversions":
            for idx, func in enumerate(buttons):
                if func == "lb":
                    display_text = "lb(kg)"
                elif func == "kg":
                    display_text = "kg(lb)"
                elif func == "K":
                    display_text = "K(°C)"
                elif func == "C":
                    display_text = "°C(K)"
                elif func == "F":
                    display_text = "F(°C)"
                elif func == "CF":
                    display_text = "°C(F)"
                else:
                    display_text = func
                button = QPushButton(display_text)
                button.setFont(font)
                button.clicked.connect(lambda _, f=func: self.insert_function(f, False))
                row = 1 + (idx // col_span)
                col = starting_col + (idx % col_span)
                layout.addWidget(button, row, col)
        
        else:
            num_buttons = len(buttons)
            num_rows = math.ceil(num_buttons / col_span)

            for idx, func in enumerate(buttons):
                button_text = f"{func}"
                button = QPushButton(button_text)
                button.setFont(font)
                button.clicked.connect(lambda _, f=func, c=(category == "Constants"): self.insert_function(f, c))
                row = 1 + (idx // col_span)
                col = starting_col + (idx % col_span)
                layout.addWidget(button, row, col)

            for extra in range(col_span * num_rows - num_buttons):
                layout.addWidget(QLabel(""), 1 + (extra // col_span), starting_col + (extra % col_span))

        starting_col += col_span

    self.function_frame.setLayout(layout)

def layout_widgets(self) -> None:
    """Arrange widgets within the window."""
    central_widget = QWidget()
    main_layout = QVBoxLayout()
    
    main_layout.addWidget(self.entry)
    
    history_layout = QHBoxLayout()
    history_layout.addWidget(self.history_text)
    history_layout.addWidget(self.scrollbar)
    main_layout.addLayout(history_layout)
    
    main_layout.addWidget(self.function_frame)
    
    central_widget.setLayout(main_layout)
    self.setCentralWidget(central_widget)

def toggle_mode(self) -> None:
    """Switch between Degrees and Radians modes."""
    self.use_degrees = not self.use_degrees
    self.mode_button.setText("Degrees" if self.use_degrees else "Radians")

def toggle_e_notation(self) -> None:
    """Toggle the E notation setting."""
    self.use_e_notation = not self.use_e_notation
    state = "On" if self.use_e_notation else "Off"
    self.e_notation_button.setText(f"E Notation: {state}")

def insert_function(self, function: str, is_constant: bool = False) -> None:
    """Insert function or constant text into the expression entry."""
    current_text = self.entry.text()
    cursor_position = self.entry.cursorPosition()
    if is_constant:
        new_text = f"{current_text[:cursor_position]}{function}{current_text[cursor_position:]}"
        new_cursor_position = cursor_position + len(function)
    else:
        new_text = f"{current_text[:cursor_position]}{function}() {current_text[cursor_position:]}"
        new_cursor_position = cursor_position + len(function) + 1
    self.entry.setText(new_text)
    self.entry.setCursorPosition(new_cursor_position)
    self.entry.setFocus()

def calculate(self) -> None:
    """Evaluate the expression and update history."""
    expression = self.entry.text().strip()
    if expression:
        result = evaluate_expression(expression, use_degrees=self.use_degrees, use_e_notation=self.use_e_notation)
        self.display_result(expression, result)
        self.entry.clear()

def display_result(self, expression: str, result: Union[float, str]) -> None:
    """Append the calculation to the history log."""
    mode = "D" if self.use_degrees else "R"
    self.history_text.append(f"[{mode}] {expression} = {result}")
    self.history_text.verticalScrollBar().setValue(
        self.history_text.verticalScrollBar().maximum()
    )

def main() -> None:
"""Run the Calculator application."""
app = QApplication([])
calculator = CalculatorGUI()
calculator.show()
app.exec()

if name == "main":
main()