组件消息现代化

This commit is contained in:
2025-11-09 12:04:01 +08:00
parent 330846a4a5
commit 35ed4e63be
4 changed files with 70 additions and 56 deletions

View File

@@ -3,6 +3,7 @@ import random
import heurams.kernel.particles as pt
import heurams.kernel.puzzles as pz
import heurams.interface.widgets as pzw
from typing import TypedDict
staging = {} # 细粒度缓存区, 是 ident -> quality 的封装
def report_to_staging(atom: pt.Atom, quality):
staging[atom.ident] = min(quality, staging[atom.ident])

View File

@@ -1,18 +1,14 @@
from textual.widgets import (
Markdown,
Label,
Static,
Button,
)
from textual.containers import Container, Horizontal, Center
from textual.screen import Screen
from textual.widget import Widget
import heurams.kernel.particles as pt
import heurams.kernel.puzzles as pz
from .base_puzzle_widget import BasePuzzleWidget
import copy
import random
from .. import shim
from textual.message import Message
class ClozePuzzle(BasePuzzleWidget):
@@ -28,31 +24,60 @@ class ClozePuzzle(BasePuzzleWidget):
self.ans = copy.copy(self.puzzle.answer)
random.shuffle(self.ans)
class RatingChanged(Message):
def __init__(self, atom: pt.Atom, rating: int, is_correct: bool) -> None:
self.atom = atom
self.rating = rating # 评分
self.is_correct = is_correct # 是否正确
super().__init__()
class InputChanged(Message):
"""输入变化消息"""
def __init__(self, current_input: list, max_length: int) -> None:
self.current_input = current_input # 当前输入
self.max_length = max_length # 最大长度
self.progress = len(current_input) / max_length # 进度
super().__init__()
def compose(self):
yield Label(self.puzzle.wording, id="sentence")
yield Label(f"当前输入: {self.inputlist}", id="inputpreview")
for i in self.ans:
self.hashtable[str(hash(i))] = i
yield Button(i, id=f"{hash(i)}")
yield Button("退格", id=f"delete")
yield Button("退格", id="delete")
def handler(self, event, type_):
# TODO: 改动:在线错误纠正
if type_ == "button":
if event.button.id == "delete":
if len(self.inputlist) > 0:
self.inputlist.pop()
else:
return 1
else:
self.inputlist.append(self.hashtable[event.button.id[6:]])
if len(self.inputlist) < len(self.puzzle.answer):
return 1
else:
if self.inputlist == self.puzzle.answer:
shim.report_to_staging(self.atom, 4)
return 0
else:
def update_preview(self):
preview = self.query_one("#inputpreview")
preview.update(f"当前输入: {self.inputlist}") # type: ignore
self.post_message(self.InputChanged(
current_input=self.inputlist.copy(),
max_length=len(self.puzzle.answer)
))
def on_button_pressed(self, event: Button.Pressed) -> None:
button_id = event.button.id
if button_id == "delete":
if len(self.inputlist) > 0:
self.inputlist.pop()
self.update_preview()
else:
answer_text = self.hashtable[button_id]
self.inputlist.append(answer_text)
self.update_preview()
if len(self.inputlist) >= len(self.puzzle.answer):
is_correct = self.inputlist == self.puzzle.answer
rating = 4 if is_correct else 2
self.post_message(self.RatingChanged(
atom=self.atom,
rating=rating,
is_correct=is_correct
))
if not is_correct:
self.inputlist = []
shim.report_to_staging(self.atom, 2)
return 2
self.update_preview()

View File

@@ -1,30 +1,17 @@
from textual.app import App, ComposeResult
from textual.events import Event
from textual.widgets import (
Collapsible,
Header,
Footer,
Markdown,
ListView,
ListItem,
Label,
Static,
Button,
)
from textual.containers import Container, Horizontal, Center
from textual.screen import Screen
from textual.containers import Center
from textual.widget import Widget
import uuid
from typing import Tuple, Dict
from typing import Dict
import heurams.kernel.particles as pt
import heurams.kernel.puzzles as pz
import re
import random
import copy
from .base_puzzle_widget import BasePuzzleWidget
from heurams.context import config_var
from .. import shim
from typing import TypedDict, List
from textual.message import Message
class RecognitionConfig(TypedDict):
__origin__: str
@@ -35,15 +22,18 @@ class RecognitionConfig(TypedDict):
class Recognition(BasePuzzleWidget):
rate_mapping = {
"ok": 5
}
def __init__(self, *children: Widget, atom: pt.Atom, alia: str = "", name: str | None = None, id: str | None = None, classes: str | None = None, disabled: bool = False, markup: bool = True) -> None:
super().__init__(*children, atom=atom, name=name, id=id, classes=classes, disabled=disabled, markup=markup)
if alia == "":
alia = "Recognition"
self.alia = alia
class RatingChanged(Message):
"""评分改变消息"""
def __init__(self, rating: int) -> None:
self.rating = rating
super().__init__()
def compose(self):
cfg: RecognitionConfig = self.atom.registry["orbital"]["puzzles"][self.alia]
delim = self.atom.registry['nucleon'].metadata["formation"]["delimiter"]
@@ -64,8 +54,8 @@ class Recognition(BasePuzzleWidget):
primary = nucleon[cfg["primary"]]
with Center():
yield Static(f"[dim]{nucleon[cfg["top_dim"]]}[/]")
yield Label(f"")
yield Static(f"[dim]{nucleon[cfg['top_dim']]}[/]")
yield Label("")
for old, new in replace_dict.items():
primary = primary.replace(old, new)
@@ -80,7 +70,7 @@ class Recognition(BasePuzzleWidget):
for item in nucleon[cfg["secondary"]]:
if isinstance(item, list):
for j in item:
yield Markdown(f"### {metadata["annotation"][item]}: {j}")
yield Markdown(f"### {metadata['annotation'][item]}: {j}")
continue
if isinstance(item, Dict):
total = ""
@@ -93,9 +83,6 @@ class Recognition(BasePuzzleWidget):
with Center():
yield Button("我已知晓", id="ok")
def handler(self, event, type_):
if type_ == "button":
if event.button.id == "ok":
shim.report_to_staging(self.atom, 5)
return 0
return -1
def on_button_pressed(self, event: Button.Pressed) -> None:
if event.button.id == "ok":
self.post_message(self.RatingChanged(5))

View File

@@ -9,15 +9,16 @@ class ClozePuzzle(BasePuzzle):
min_denominator: 最小概率倒数(如占所有可生成填空数的 1/7 中的 7, 若期望值小于 1, 则取 1)
"""
def __init__(self, text: str, delimiter: str = "/", min_denominator: int):
def __init__(self, text: str, min_denominator: int, delimiter: str = "/"):
self.text = text
self.min_denominator = min_denominator
self.wording = "填空题 - 尚未刷新谜题"
self.answer = ["填空题 - 尚未刷新谜题"]
self.delimiter = delimiter
def refresh(self): # 刷新谜题
placeholder = "___SLASH___"
tmp_text = self.text.replace(delimiter, placeholder)
tmp_text = self.text.replace(self.delimiter, placeholder)
words = tmp_text.split(placeholder)
if not words:
return