Improve concept derivation UI

This commit is contained in:
IRBorisov 2024-04-05 20:04:12 +03:00
parent f03fd337ba
commit 2fbbec0466
13 changed files with 60 additions and 23 deletions

View File

@ -11,18 +11,18 @@ interface InfoConstituentaProps extends CProps.Div {
function InfoConstituenta({ data, className, ...restProps }: InfoConstituentaProps) {
return (
<div className={clsx('dense', className)} {...restProps}>
<div className={clsx('dense min-w-[15rem]', className)} {...restProps}>
<h2>Конституента {data.alias}</h2>
{data.derived_alias ? (
{data.derived_from_alias ? (
<p>
<b>Основана на: </b>
{data.derived_alias}
<b>Основание: </b>
{data.derived_from_alias}
</p>
) : null}
{data.derived_children.length > 0 ? (
{data.derived_children_alias.length > 0 ? (
<p>
<b>Порождает: </b>
{data.derived_children.join(', ')}
{data.derived_children_alias.join(', ')}
</p>
) : null}
<p>

View File

@ -6,6 +6,7 @@ function HelpConstituenta() {
return (
<div className='dense'>
<h1>Редактор конституент</h1>
<p>При выделении также подсвечиваются производные и основание</p>
<p><b>Сохранить изменения</b>: Ctrl + S или клик по кнопке Сохранить</p>
<p className='mt-1'><b>Формальное определение</b></p>
<p>- Ctrl + Пробел дополняет до незанятого имени</p>

View File

@ -57,7 +57,7 @@ function DlgGraphParams({ hideWindow, initial, onConfirm }: DlgGraphParamsProps)
/>
<Checkbox
label='Свернуть производные'
title='Отображать производные понятия вместе с основным'
title='Не отображать производные понятия'
value={params.foldDerived}
setValue={value => updateParams({ foldDerived: value })}
/>

View File

@ -97,8 +97,9 @@ export interface IConstituenta extends IConstituentaMeta {
status: ExpressionStatus;
is_template: boolean;
derived_from: ConstituentaID;
derived_alias?: string;
derived_children: string[];
derived_from_alias?: string;
derived_children: number[];
derived_children_alias: string[];
parse: {
status: ParsingStatus;
valueClass: ValueClass;

View File

@ -37,6 +37,7 @@ export function loadRSFormData(input: IRSFormData): IRSForm {
derivationLookup.set(cst.id, cst.id);
cst.derived_from = cst.id;
cst.derived_children = [];
cst.derived_children_alias = [];
cst.status = inferStatus(cst.parse.status, cst.parse.valueClass);
cst.is_template = inferTemplate(cst.definition_formal);
cst.cst_class = inferClass(cst.cst_type, cst.is_template);
@ -72,8 +73,9 @@ export function loadRSFormData(input: IRSFormData): IRSForm {
if (resolvedInput.size === 1 && isSimpleExpression(definition)) {
const parent = result.items.find(item => item.id === resolvedInput.values().next().value)!;
cst.derived_from = parent.id;
cst.derived_alias = parent.alias;
parent.derived_children.push(cst.alias);
cst.derived_from_alias = parent.alias;
parent.derived_children_alias.push(cst.alias);
parent.derived_children.push(cst.id);
derivationLookup.set(cst.id, parent.id);
}
});
@ -208,6 +210,7 @@ export function createMockConstituenta(id: ConstituentaID, alias: string, commen
id: id,
derived_from: id,
derived_children: [],
derived_children_alias: [],
order: -1,
schema: -1,
alias: alias,

View File

@ -19,6 +19,8 @@ const simpleExpressionData = [
['pr1(S1)', 'true'],
['red(S1)', 'true'],
['red(Pr1(F1[α,σ]))', 'true'],
['(X1)', 'false'],
['(X1)', 'false'],
['D{(α,β)∈D6×D6 | α≠β & α∩β≠∅}', 'false'],
['I{(β,α) | α:∈D2; σ:=F5[α]; β:∈σ}', 'false'],
['∀σ∈S1 (F1[σ]×F1[σ])∩D11=∅', 'false']

View File

@ -24,7 +24,7 @@ export function extractGlobals(expression: string): Set<string> {
* Check if expression is simple derivation.
*/
export function isSimpleExpression(text: string): boolean {
return !COMPLEX_SYMBOLS_REGEXP.test(text);
return !text.match(COMPLEX_SYMBOLS_REGEXP);
}
/**

View File

@ -92,7 +92,9 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
result.push({
id: String(node.id),
fill: colorBgGraphNode(cst, coloringScheme, colors),
label: cst.term_resolved && !filterParams.noText ? `${cst.alias}: ${cst.term_resolved}` : cst.alias
label: cst.alias,
subLabel: !filterParams.noText ? cst.term_resolved : undefined,
size: cst.derived_from_alias ? 1 : 2
});
}
});
@ -164,6 +166,16 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
}
}
const handleFoldDerived = useCallback(() => {
setFilterParams(prev => ({
...prev,
foldDerived: !prev.foldDerived
}));
setTimeout(() => {
setToggleResetView(prev => !prev);
}, TIMEOUT_GRAPH_REFRESH);
}, [setFilterParams, setToggleResetView]);
const graph = useMemo(
() => (
<TermGraph
@ -224,12 +236,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
onDelete={handleDeleteCst}
onResetViewpoint={() => setToggleResetView(prev => !prev)}
toggleOrbit={() => setOrbit(prev => !prev)}
toggleFoldDerived={() =>
setFilterParams(prev => ({
...prev,
foldDerived: !prev.foldDerived
}))
}
toggleFoldDerived={handleFoldDerived}
toggleNoText={() =>
setFilterParams(prev => ({
...prev,

View File

@ -74,7 +74,7 @@ function GraphToolbar({
onClick={toggleNoText}
/>
<MiniButton
title={!foldDerived ? 'Скрыть производные' : 'Отображать производные'}
title={!foldDerived ? 'Скрыть производные' : 'Отобразить производные'}
icon={
!foldDerived ? (
<IconClustering size='1.25rem' className='icon-green' />

View File

@ -45,8 +45,8 @@ function TermGraph({
const { selections, setSelections } = useSelection({
ref: graphRef,
nodes,
edges,
nodes: nodes,
edges: edges,
type: 'multi'
});
@ -110,6 +110,8 @@ function TermGraph({
onNodeClick={handleNodeClick}
onNodePointerOver={handleHoverIn}
onNodePointerOut={handleHoverOut}
minNodeSize={4}
maxNodeSize={8}
cameraMode={orbit ? 'orbit' : is3D ? 'rotate' : 'pan'}
layoutOverrides={
layout.includes('tree') ? { nodeLevelRatio: nodes.length < TREE_SIZE_MILESTONE ? 3 : 1 } : undefined

View File

@ -48,7 +48,7 @@ function useGraphFilter(schema: IRSForm | undefined, params: GraphFilterParams)
}
if (params.foldDerived) {
schema.items.forEach(cst => {
if (cst.derived_alias) {
if (cst.derived_from_alias) {
graph.foldNode(cst.id);
}
});

View File

@ -108,6 +108,18 @@ function ConstituentsTable({ items, activeID, onOpenEdit, maxHeight, denseThresh
style: {
backgroundColor: colors.bgSelected
}
},
{
when: (cst: IConstituenta) => cst.derived_from === activeID && cst.id !== activeID,
style: {
backgroundColor: colors.bgOrange50
}
},
{
when: (cst: IConstituenta) => activeID !== undefined && cst.derived_children.includes(activeID),
style: {
backgroundColor: colors.bgGreen50
}
}
],
[activeID, colors]

View File

@ -35,6 +35,9 @@ export interface IColorTheme {
bgTeal: string;
bgOrange: string;
bgGreen50: string;
bgOrange50: string;
fgRed: string;
fgGreen: string;
fgBlue: string;
@ -72,6 +75,9 @@ export const lightT: IColorTheme = {
bgTeal: 'hsl(192, 089%, 081%)',
bgOrange: 'hsl(028, 100%, 075%)',
bgGreen50: 'hsl(100, 100%, 090%)',
bgOrange50: 'hsl(028, 100%, 095%)',
fgRed: 'hsl(000, 090%, 045%)',
fgGreen: 'hsl(100, 090%, 035%)',
fgBlue: 'hsl(235, 100%, 050%)',
@ -109,6 +115,9 @@ export const darkT: IColorTheme = {
bgTeal: 'hsl(192, 080%, 030%)',
bgOrange: 'hsl(035, 100%, 035%)',
bgGreen50: 'hsl(100, 080%, 017%)',
bgOrange50: 'hsl(035, 100%, 015%)',
fgRed: 'hsl(000, 080%, 045%)',
fgGreen: 'hsl(100, 080%, 035%)',
fgBlue: 'hsl(235, 100%, 080%)',