Skip to content
Snippets Groups Projects
Commit 1205717d authored by Martin Högstedt's avatar Martin Högstedt
Browse files

changing bases results in each cell being empty, dont know why

parent fa064bdf
No related branches found
No related tags found
No related merge requests found
Pipeline #134646 failed
from typing import Optional
from math import ceil
from qtpy.QtCore import Qt
from qtpy.QtCore import Signal as pyqtSignal
from qtpy.QtWidgets import (
QComboBox,
QButtonGroup,
QDialog,
QErrorMessage,
QHBoxLayout,
QLineEdit,
QPushButton,
QHeaderView,
QRadioButton,
QTableWidget,
QTableWidgetItem,
QVBoxLayout,
QWidget,
)
from simudator.core import Module
from simudator.core.modules import Memory
from simudator.gui.formatting import Format, FormatInfo, format_to_str
class MemoryTable(QTableWidget):
"""
A class showing the contents of a memory module in a QTableWidget.
This class assumes that the size of the memory module will remain constant.
Parameters
----------
memory_module: Memory
An instance of the Memory base class.
column_size: int
An integer specifying the number of columns, optional.
format_info : FormatInfo
Optional formatter for formatting each cell in the memory table.
"""
state_edited = pyqtSignal()
def __init__(
self,
memory_module: Memory,
format_info: FormatInfo | None = None,
column_size=-1,
):
super().__init__()
self._format_info = format_info
self._memory = memory_module
self._column_size = column_size
self._memory_size = len(self._memory.get_state()["memory"])
self._set_column_size()
self.setColumnCount(self._column_size)
rows = ceil(self._memory_size / self._column_size)
self.setRowCount(rows)
self._init_table_items(self._column_size, rows)
self.setHorizontalHeaderLabels(["+" + str(i) for i in range(4)])
self.set_editable(False)
self._errorMessageWidget = QErrorMessage()
vertical_headers = []
for i in range(0, self._memory_size, self._column_size):
vertical_headers.append(str(hex(i)))
self.setVerticalHeaderLabels(vertical_headers)
self._tt = 0
self.update()
# Signal used to detect when the user has edited a cell
# This code can only be called after the initial self.update().
# When the QTableWidget is initialized it currently fills each celll with empty strings.
# It also signals cellChanged for each cell it initializes. Thus _on_cell_changed
# is called for each cell and tries to save the cells empty string into the modules memory as
# an integer.
self.cellChanged.connect(self._on_cell_changed)
def update(self):
"""
Update the content of this widget to reflect the content of the memory module.
"""
print(self._tt)
self._tt += 1
memory_content = self._memory.get_state()["memory"]
for i in range(self._memory_size):
value = memory_content[i]
row = i // self._column_size
col = i % self._column_size
if self._format_info:
value = format_to_str(self._format_info, value)
print("-" * 20)
print(self._format_info.selected_format)
print(value)
print("-" * 20)
else:
value = str(value)
if value != "":
self.set_item(row, col, value)
def set_item(self, row: int, col: int, text: str) -> None:
"""Set the text at specified table cell to the given text.
Parameters
----------
row: int
The items row position in the table.
col: int
The items column position in the table.
text: str
The text to be displayed.
"""
item = QTableWidgetItem(text)
self.setItem(row, col, item)
def set_editable(self, editable: bool) -> None:
"""
Set the text to be editable on ``True``, uneditable on ``False``.
Parameters
----------
editable: bool
Sets the text to be editable on ``True``, uneditable on ``False``.
"""
if editable:
self.setEditTriggers(self.AllEditTriggers)
else:
self.setEditTriggers(self.NoEditTriggers)
def _init_table_items(self, cols: int, rows: int) -> None:
for col in range(cols):
for row in range(rows):
item = QTableWidgetItem()
self.setItem(row, col, item)
def _set_column_size(self) -> None:
"""
Set the column size to a reasonable value if the size was not given to the constructor.
This function assumes that the attributes `column_size` and `memory_size` are set before it is called.
"""
if not self._column_size == -1:
return
if self._memory_size > 200:
self._column_size = 4
return
if self._memory_size > 100:
self._column_size = 2
return
self._column_size = 1
return
def _on_cell_changed(self, row, col):
state = self._memory.get_state()
item = self.item(row, col)
value = item.text()
if value == "":
return
index = row * self._column_size + col
state['memory'][index] = value
self._memory.set_state(state)
self.state_edited.emit()
class MemoryContentDialog(QDialog):
accepted = pyqtSignal(str, str, str, name="accepted")
"""
A dialog for letting the user edit the state of a processor modules memory.
Parameters
----------
module : Module
The module to edit the memory of.
parent : QWidget | None
Optional parent widget of this dialog.
flags : Qt.WindowFlags | Qt.WindowType
Optional window flags for the window of the dialog.
format_info : FormatInfo
Optional formatter for formatting each cell in the memory table.
"""
state_edited = pyqtSignal()
def __init__(
self,
memory: Module,
parent: Optional['QWidget'] = None,
memory_module: Memory,
parent: QWidget | None = None,
flags: Qt.WindowFlags | Qt.WindowType = Qt.WindowFlags(),
format_info: FormatInfo | None = None,
) -> None:
super().__init__(parent, flags)
self._memory_module = memory_module
self._format_info = format_info
self._add_layout()
self._add_edit_buttons()
self._add_formatting_buttons()
# Sets the size of each column to the smallest possible width that allows all content in each box to be visible self._memory_table.horizontalHeader().setSectionResizeMode(
self._memory_table.horizontalHeader().setSectionResizeMode(
QHeaderView.ResizeToContents
)
self._memory_table.update()
def _add_layout(self):
# Create a layout that expands vertically
# so that the buttons can be displayed below the
# memory content
self._layout = QVBoxLayout(self)
self._memory_table = MemoryTable(self._memory_module, self._format_info)
self._memory_table.state_edited.connect(self.state_edited)
self._layout.addWidget(self._memory_table)
def _add_edit_buttons(self):
# Create edit/view buttons, they are exclusive by default
self._edit_button = QRadioButton("Edit")
self._view_button = QRadioButton("View")
self._edit_group = QButtonGroup()
self._edit_group.addButton(self._edit_button, 1)
self._edit_group.addButton(self._view_button, 2)
# Connect them to the 'set_edit' function
self._edit_group.buttonClicked.connect(self._set_edit)
self._edit_button_layout = QHBoxLayout()
self._edit_button_layout.addWidget(self._edit_button)
self._edit_button_layout.addWidget(self._view_button)
self._layout.addLayout(self._edit_button_layout)
# Set the memory to be uneditable on startup
self._view_button.toggle()
def _add_formatting_buttons(self):
self.memory = memory
self.memory_name = memory.get_state()['name']
# If format info is 'None' do nothing
if not self._format_info:
return
adresses = [str(i) for i in range(len(memory.get_state()['memory']))]
# If there are no supported_formats we want to avoid creating
# a new button group since it will take up space that is not used
if len(self._format_info.supported_formats) == 0:
return
self.adressSelectWidget = QComboBox()
self.adressSelectWidget.addItems(adresses)
self.adressSelectWidget.activated.connect(self.updateValue)
self.adressSelectWidget.setEditable(True)
self._format_group = QButtonGroup()
self._format_button_layout = QHBoxLayout()
format_names = [format.name for format in self._format_info.supported_formats]
self.valuesWidget = QLineEdit()
# Create formatting buttons, they are exclusive by default
# Each button will be mapped to the value of the enums
for format in Format:
okButton = QPushButton('OK')
okButton.clicked.connect(self.signalAccepted)
cancelButton = QPushButton('Cancel')
cancelButton.clicked.connect(self.close)
name = format.name
id = format.value[0]
hboxLayout = QHBoxLayout()
hboxLayout.addWidget(self.adressSelectWidget, 0)
hboxLayout.addWidget(self.valuesWidget, 1)
hboxLayout.addWidget(okButton)
hboxLayout.addWidget(cancelButton)
self.setLayout(hboxLayout)
if name in format_names:
button = QRadioButton(name)
self._format_group.addButton(button, id)
self._format_button_layout.addWidget(button)
self.show()
self.updateValue()
self._layout.addLayout(self._format_button_layout)
self._format_group.buttonClicked.connect(self._set_format)
def updateValue(self) -> None:
selectedAdress = int(self.adressSelectWidget.currentText(), 16)
memory_content = self.memory.get_state()['memory']
value = memory_content[selectedAdress]
self.valuesWidget.setText(str(value))
def _set_edit(self):
pressed_button_id = self._edit_group.checkedId()
if pressed_button_id == 1:
self._memory_table.set_editable(True)
if pressed_button_id == 2:
self._memory_table.set_editable(False)
def signalAccepted(self) -> None:
adress = self.adressSelectWidget.currentText()
enteredValues = self.valuesWidget.text()
self.accepted.emit(self.memory_name, adress, enteredValues)
self.close()
def _set_format(self):
pressed_button_id = self._format_group.checkedId()
self._format_info.selected_format = pressed_button_id
self._memory_table.update()
......@@ -104,4 +104,3 @@ class ModuleStateDialog(QDialog):
except ValueError as e:
# TODO: error handling
pass
......@@ -3,7 +3,9 @@ from enum import Enum, auto
from PyQt5.QtWidgets import QAction
from simudator.core.module import Module
from simudator.gui.dialogs.memory_content_dialog import MemoryContentDialog
from simudator.gui.dialogs.module_state_dialog import ModuleStateDialog
from simudator.gui.formatting import FormatInfo
from simudator.gui.module_graphics_item.module_widget import ModuleWidget
......@@ -14,6 +16,7 @@ class ActionType(Enum):
"""
EditState = (auto(),)
EditMemory = (auto(),)
def edit_state_action(module: Module, module_widget: ModuleWidget) -> QAction:
......@@ -41,6 +44,42 @@ def edit_state_action(module: Module, module_widget: ModuleWidget) -> QAction:
def action_triggered():
dialog = ModuleStateDialog(module, module_widget)
dialog.state_edited.connect(module_widget.state_changed)
dialog.exec()
action.triggered.connect(action_triggered)
return action
def edit_memory_action(
module: Module, module_widget: ModuleWidget, format_info: FormatInfo | None = None
) -> QAction:
"""
Create a QAction for opening a memory-edit dialog for a module widget.
The dialog triggers the state_changed signal of the module widget if the
user edites the contentet in the dialog.
Parameters
----------
module : Module
The module that should be edited when triggering the created edit action.
module_widget : ModuleWidget
The module widget for the module that should be edited. Used for
displaying and parsing information correctly.
format_info : FormatInfo
Optional formatter for formatting each cell in the memory table.
Returns
-------
QAction
A Qt action for opening a dialog for editing the state of a modules memory.
Intended to be added as an action to the given module widget.
"""
action = QAction("Edit memory", module_widget)
def action_triggered():
dialog = MemoryContentDialog(module, format_info=format_info)
dialog.state_edited.connect(module_widget.state_changed)
dialog.exec()
action.triggered.connect(action_triggered)
return action
......@@ -64,4 +103,3 @@ def toggle_ports_action(module_widget: ModuleWidget) -> QAction:
action = QAction("Toggle ports", module_widget)
action.triggered.connect(module_widget.toggle_ports)
return action
import sys
import traceback
from enum import Enum
from qtpy.QtWidgets import QButtonGroup, QHBoxLayout, QHeaderView, QRadioButton
......
......@@ -340,4 +340,3 @@ class ProcessorHandler(QObject):
by the user.
"""
pass
......@@ -4,6 +4,9 @@ from simudator.cli.cli import CLI
from simudator.core.modules.integer_register import IntegerRegister
from simudator.core.processor import Processor, Signal
from simudator.gui.gui import GUI
from simudator.gui.module_graphics_item.actions import edit_memory_action, edit_state_action
from simudator.gui.module_graphics_item.module_widget import ModuleWidget
from simudator.gui.formatting import Format, FormatInfo
from simudator.processor.mia.gui import (
AluGraphicsItem,
ArGraphicsItem,
......@@ -384,6 +387,18 @@ class MIA_CPU(Processor):
widget = MiaMemoryGraphicsItem(module)
gui.add_module_graphics_item(widget)
pm = self.get_module("PM")
gui_pm = ModuleWidget(pm, {}, [])
action = edit_memory_action(pm, gui_pm, FormatInfo(FormatInfo.NUMERICAL_FORMATS, Format.Hex, bit_length=16))
gui_pm.addAction(action)
gui.add_module_widget(gui_pm)
ar = self.get_module("AR")
gui_ar = ModuleWidget(ar, {"value": FormatInfo(FormatInfo.NUMERICAL_FORMATS, Format.Hex, bit_length=16)}, [])
action = edit_state_action(ar, gui_ar)
gui_ar.addAction(action)
gui.add_module_widget(gui_ar)
gui.add_all_signals()
gui.show()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment