Seperate the call based on best python practice to increase readability and maintainability. Python 3.12 code:  class CalculatorGUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.use_degrees = True
        self.variables = {}
        self.history_entries = []
        self.text_functions = ['capitalize', 'duplicates']
        self.setup_window()
        self.create_widgets()
        self.layout_widgets()
        self.connect_signals()
        self.load_saved_data()

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

    def create_widgets(self) -> None:
        """Create all widgets used in the application."""
        font = QFont()
        font.setPointSize(12)
        font.setFamily('Literata')

        self.entry = QLineEdit()
        self.entry.setFont(font)
        self.entry.setPlaceholderText('Enter expression')
        self.entry.setClearButtonEnabled(True)
        self.entry.returnPressed.connect(self.calculate)

        self.history_text = QTextEdit()
        self.history_text.setFont(font)
        self.history_text.setReadOnly(True)
        self.history_text.setStyleSheet("position: relative;")

        self.scrollbar = QScrollBar(Qt.Vertical)
        self.history_text.setVerticalScrollBar(self.scrollbar)

        # --- Existing Buttons ---

        self.search_button = QPushButton("🔍", self.history_text)
        self.search_button.setFixedSize(24, 24)
        self.search_button.setToolTip("Search History")
        self.search_button.setStyleSheet("""
            QPushButton {
                border: none;
                background-color: rgba(255, 255, 255, 200);
                font-size: 14px;
                border-radius: 12px;
            }
            QPushButton:hover {
                background-color: rgba(234, 235, 239, 255);
                color: white;
            }
        """)
        self.search_button.clicked.connect(self.toggle_search)
        self.search_button.raise_()

        self.delete_button = LongPressButton("🗑️", self.history_text, hold_duration=3000)
        self.delete_button.setFixedSize(24, 24)
        self.delete_button.setToolTip("Clear History (Hold for 3 seconds)")
        self.delete_button.setStyleSheet("""
            QPushButton {
                border: none;
                background-color: rgba(255, 255, 255, 200);
                font-size: 14px;
                border-radius: 12px;
            }
            QPushButton:hover {
                background-color: rgba(234, 235, 239, 255);
                color: white;
            }
        """)
        self.delete_button.longPressed.connect(self.clear_history)
        self.delete_button.raise_()

        self.vars_button = QPushButton("🧮", self.history_text)
        self.vars_button.setFixedSize(24, 24)
        self.vars_button.setToolTip("Show Variables")
        self.vars_button.setStyleSheet("""
            QPushButton {
                border: none;
                background-color: rgba(255, 255, 255, 200);
                font-size: 14px;
                border-radius: 12px;
            }
            QPushButton:hover {
                background-color: rgba(234, 235, 239, 255);
                color: white;
            }
        """)
        self.vars_button.clicked.connect(self.toggle_vars_overlay)
        self.vars_button.raise_()

        self.vars_overlay = QLineEdit(self.history_text)
        self.vars_overlay.setReadOnly(True)
        self.vars_overlay.setPlaceholderText("a = 1, b = 85, ...")
        self.vars_overlay.setFixedHeight(24)
        self.vars_overlay.setFixedWidth(300)
        self.vars_overlay.setStyleSheet("""
            QLineEdit {
                border: 1px solid gray;
                border-radius: 4px;
                padding: 2px 4px;
                background-color: white;
            }
        """)
        self.vars_overlay.setVisible(False)

        self.vars_delete_button = LongPressButton("🗑️", self.vars_overlay, hold_duration=3000)
        self.vars_delete_button.setFixedSize(16, 16)
        self.vars_delete_button.setToolTip("Clear Variables (Hold for 3 seconds)")
        self.vars_delete_button.setStyleSheet("""
            QPushButton {
                border: none;
                background-color: rgba(255, 255, 255, 200);
                font-size: 10px;
                border-radius: 8px;
            }
            QPushButton:hover {
                background-color: rgba(234, 235, 239, 255);
                color: white;
            }
        """)
        self.vars_delete_button.longPressed.connect(self.clear_variables)
        self.vars_delete_button.setVisible(False)

        self.search_bar = QLineEdit(self.history_text)
        self.search_bar.setPlaceholderText("Search...")
        self.search_bar.setFixedHeight(24)
        self.search_bar.setFixedWidth(300)
        self.search_bar.setVisible(False)
        self.search_bar.setStyleSheet("""
            QLineEdit {
                border: 1px solid gray;
                border-radius: 4px;
                padding: 2px 4px;
                background-color: white;
            }
        """)
        self.search_bar.textChanged.connect(self.filter_history)
        self.search_bar.setClearButtonEnabled(True)

        self.save_button = QPushButton("💾", self.history_text)
        self.save_button.setFixedSize(24, 24)
        self.save_button.setToolTip("Export History and Variables")
        self.save_button.setStyleSheet("""
            QPushButton {
                border: none;
                background-color: rgba(255, 255, 255, 200);
                font-size: 14px;
                border-radius: 12px;
            }
            QPushButton:hover {
                background-color: rgba(234, 235, 239, 255);
                color: white;
            }
        """)
        self.save_button.clicked.connect(self.save_data)
        self.save_button.raise_()

        self.load_button = QPushButton("📂", self.history_text)
        self.load_button.setFixedSize(24, 24)
        self.load_button.setToolTip("Import History and Variables")
        self.load_button.setStyleSheet("""
            QPushButton {
                border: none;
                background-color: rgba(255, 255, 255, 200);
                font-size: 14px;
                border-radius: 12px;
            }
            QPushButton:hover {
                background-color: rgba(234, 235, 239, 255);
                color: white;
            }
        """)
        self.load_button.clicked.connect(self.load_data)
        self.load_button.raise_()

        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": []
        }
        self.function_frame = QFrame()
        self.create_function_buttons(font)

    def create_function_buttons(self, font: QFont) -> None:
        """Create and arrange function buttons."""
        layout = QGridLayout()
        categories = [("Functions", 3), ("Conversions", 2), ("Text", 2), ("Constants", 2), ("Settings", 1)]
        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, is_text_function=(f in self.text_functions))
                    )
                    layout.addWidget(button, (i // 3) + 1, starting_col + (i % 3))

            elif category == "Settings":
                self.mode_button = QPushButton("Degrees")
                self.mode_button.setFont(font)
                self.mode_button.clicked.connect(self.toggle_mode)
                layout.addWidget(self.mode_button, 1, starting_col, 1, 1)

            elif category == "Conversions":
                conversion_mapping = {
                    "lb": "KilogramToPound",
                    "kg": "PoundToKilogram",
                    "K": "CelsiusToKelvin",
                    "C": "KelvinToCelsius",
                    "F": "CelsiusToFahrenheit",
                    "CF": "FahrenheitToCelsius"
                }

                for idx, func in enumerate(buttons):
                    display_text = {
                        "lb": "lb(Kg)",
                        "kg": "kg(lb)",
                        "K": "K(°C)",
                        "C": "°C(K)",
                        "F": "F(°C)",
                        "CF": "°C(F)"
                    }.get(func, func)

                    button = QPushButton(display_text)
                    button.setFont(font)

                    function_to_insert = conversion_mapping.get(func, func)

                    button.clicked.connect(
                        lambda _, f=function_to_insert: self.insert_function(f, is_text_function=False)
                    )
                    row, col = 1 + idx // 2, starting_col + idx % 2
                    layout.addWidget(button, row, col)

            elif category == "Text":
                for idx, func in enumerate(buttons):
                    button = QPushButton(func)
                    button.setFont(font)
                    button.clicked.connect(
                        lambda _, f=func: self.insert_function(f, is_text_function=True)
                    )
                    row, col = 1 + idx // col_span, starting_col + idx % col_span
                    layout.addWidget(button, row, col)

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

            total_rows = math.ceil(len(buttons) / col_span)
            
            for extra in range(col_span * total_rows - len(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 all widgets in the main 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 connect_signals(self) -> None:
        """Connect global signals."""
        QApplication.instance().focusChanged.connect(self.on_focus_changed)

    def toggle_mode(self) -> None:
        """Toggle between degrees and radians for trigonometric functions."""
        self.use_degrees = not self.use_degrees
        self.mode_button.setText("Degrees" if self.use_degrees else "Radians")

    def insert_function(self, function: str, is_constant: bool = False, is_text_function: bool = False) -> None:
        """Insert the selected function into the entry field."""
        current_text = self.entry.text()
        cursor_position = self.entry.cursorPosition()
        if is_constant:
            new_text = f"{current_text[:cursor_position]}{function} "
            new_cursor_position = cursor_position + len(function) + 1
        elif is_text_function and function in self.text_functions:
            new_text = f'{current_text[:cursor_position]}{function}() {current_text[cursor_position:]}'
            new_cursor_position = cursor_position + len(function) + 1
        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 entered by the user."""
        expression = self.entry.text().strip()
        if expression:
            result = evaluate_expression(
                expression, self.variables, use_degrees=self.use_degrees
            )
            self.display_result(expression, result)
            self.entry.clear()

    def display_result(self, expression: str, result: Union[float, str]) -> None:
        """Display the result in the history."""
        mode = "D" if self.use_degrees else "R"
        if re.match(r'^\s*[a-zA-Z_]\w*\s*=\s*.+$', expression):
            history_entry = f"[{mode}] {result}"
        else:
            history_entry = f"[{mode}] {expression} = {result}"
        self.history_entries.append(history_entry)
        self.refresh_history()
        self.history_text.verticalScrollBar().setValue(
            self.history_text.verticalScrollBar().maximum()
        )

    def toggle_search(self) -> None:
        """Toggle the visibility of the search bar."""
        if self.search_bar.isVisible():
            self.search_bar.setVisible(False)
        else:
            self.search_bar.setVisible(True)
            self.search_bar.setFocus()
        self.update_overlay_buttons_position()

    def filter_history(self, text: str) -> None:
        """Filter the history based on search text."""
        self.refresh_history(text)

    def refresh_history(self, filter_text: str = "") -> None:
        """Refresh the history display, optionally filtering results."""
        self.history_text.clear()
        for entry in self.history_entries:
            if filter_text.lower() in entry.lower():
                self.history_text.append(entry)

    def resizeEvent(self, event) -> None:
        """Handle window resize events."""
        super().resizeEvent(event)
        self.update_overlay_buttons_position()

    def update_overlay_buttons_position(self) -> None:
        """Update the position of overlay buttons based on current window size."""
        size = self.history_text.viewport().size()

        margin_right = 5
        margin_top = 5
        spacing = 5

        available_width = size.width()

        search_offset = self.search_bar.width() + spacing if self.search_bar.isVisible() else 0
        load_offset = self.load_button.width() + spacing if self.load_button.isVisible() else 0
        save_offset = self.save_button.width() + spacing if self.save_button.isVisible() else 0

        self.search_button.move(
            available_width - search_offset - self.search_button.width() - margin_right,
            margin_top
        )

        vars_offset = self.vars_overlay.width() + spacing if self.vars_overlay.isVisible() else 0
        vars_button_y = self.search_button.y() + self.search_button.height() + spacing
        self.vars_button.move(
            available_width - vars_offset - self.vars_button.width() - margin_right,
            vars_button_y
        )

        save_button_y = self.vars_button.y() + self.vars_button.height() + spacing
        self.save_button.move(
            available_width - self.save_button.width() - margin_right,
            save_button_y
        )

        load_button_y = self.save_button.y() + self.save_button.height() + spacing
        self.load_button.move(
            available_width - self.load_button.width() - margin_right,
            load_button_y
        )

        delete_button_y = self.load_button.y() + self.load_button.height() + spacing
        self.delete_button.move(
            available_width - self.delete_button.width() - margin_right,
            delete_button_y
        )

        if self.vars_overlay.isVisible():
            self.vars_overlay.move(
                available_width - self.vars_overlay.width() - margin_right,
                self.vars_button.y()
            )
            self.vars_delete_button.move(
                self.vars_overlay.width() - self.vars_delete_button.width() - margin_right,
                (self.vars_overlay.height() - self.vars_delete_button.height()) // 2
            )
            self.vars_delete_button.setVisible(True)

        if self.search_bar.isVisible():
            self.search_bar.move(
                available_width - self.search_bar.width() - margin_right,
                margin_top
            )

    def on_focus_changed(self, old: QWidget, new: QWidget) -> None:
        """Handle focus changes to hide overlays when necessary."""
        if self.vars_overlay.isVisible() and new not in {self.vars_overlay, self.vars_delete_button, self.vars_button}:
            self.vars_overlay.setVisible(False)
            self.vars_delete_button.setVisible(False)
            self.update_overlay_buttons_position()
        if self.search_bar.isVisible() and not self.search_bar.text().strip() and new != self.search_bar:
            self.toggle_search()

    def showEvent(self, event) -> None:
        """Handle the show event to position overlays correctly."""
        super().showEvent(event)
        self.update_overlay_buttons_position()

    def clear_history(self) -> None:
        """Clear the calculation history."""
        self.history_entries.clear()
        self.refresh_history()

    def toggle_vars_overlay(self) -> None:
        """Toggle the visibility of the variables overlay."""
        if self.vars_overlay.isVisible():
            self.vars_overlay.setVisible(False)
            self.vars_delete_button.setVisible(False)
        else:
            self.update_vars_overlay()
            self.vars_overlay.setVisible(True)
            self.vars_delete_button.setVisible(True)
        self.update_overlay_buttons_position()

    def update_vars_overlay(self) -> None:
        """Update the text displayed in the variables overlay."""
        if not self.variables:
            self.vars_overlay.setText("No variables assigned.")
        else:
            vars_text = ", ".join(f"{var} = {value}" for var, value in self.variables.items())
            self.vars_overlay.setText(vars_text)

    def clear_variables(self) -> None:
        """Clear all assigned variables."""
        self.variables.clear()
        self.update_vars_overlay()
        self.vars_overlay.setVisible(True)
        self.vars_delete_button.setVisible(True)

    def save_data(self) -> None:
        """Save history and variables to a file."""
        try:
            data = {
                'history': self.history_entries,
                'variables': self.variables
            }

            options = QFileDialog.Options()
            options |= QFileDialog.DontUseNativeDialog
            file_path, _ = QFileDialog.getSaveFileName(
                self,
                "Save Calculator Data",
                "",
                "JSON Files (*.json);;All Files (*)",
                options=options
            )
            if file_path:
                with open(file_path, 'w') as f:
                    json.dump(data, f, indent=4)
                QMessageBox.information(self, "Save Successful", f"Data saved to {file_path}")
        except Exception as e:
            QMessageBox.critical(self, "Save Failed", f"An error occurred while saving: {e}")

    def load_data(self) -> None:
        """Load history and variables from a file."""
        try:
            options = QFileDialog.Options()
            options |= QFileDialog.DontUseNativeDialog
            file_path, _ = QFileDialog.getOpenFileName(
                self,
                "Load Calculator Data",
                "",
                "JSON Files (*.json);;All Files (*)",
                options=options
            )
            if file_path:
                with open(file_path, 'r') as f:
                    data = json.load(f)
                if 'history' in data and 'variables' in data:
                    self.history_entries = data['history']
                    self.variables = data['variables']
                    self.refresh_history()
                    self.update_vars_overlay()
                    QMessageBox.information(self, "Load Successful", f"Data loaded from {file_path}")
                else:
                    QMessageBox.warning(self, "Invalid Data", "The selected file does not contain valid calculator data.")
        except Exception as e:
            QMessageBox.critical(self, "Load Failed", f"An error occurred while loading: {e}")

    def load_saved_data(self) -> None:
        """Load history and variables from a default save file if it exists."""
        default_save = 'calculator_save.json'
        if os.path.exists(default_save):
            try:
                with open(default_save, 'r') as f:
                    data = json.load(f)
                self.history_entries = data.get('history', [])
                self.variables = data.get('variables', {})
                self.refresh_history()
                self.update_vars_overlay()
            except Exception as e:
                QMessageBox.warning(self, "Load Failed", f"Failed to load saved data: {e}")

    def closeEvent(self, event) -> None:
        """Save data before closing the application."""
        try:
            data = {
                'history': self.history_entries,
                'variables': self.variables
            }
            with open('calculator_save.json', 'w') as f:
                json.dump(data, f, indent=4)
        except Exception as e:
            QMessageBox.warning(self, "Auto-Save Failed", f"Failed to auto-save data: {e}")
        event.accept()