From 42744c6b169c9a969ed821a2df89dc62d07b58e0 Mon Sep 17 00:00:00 2001 From: Alexander Zhirov Date: Wed, 7 Jan 2026 17:20:47 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=8D=D0=BA=D1=80=D0=B0=D0=BD=D0=B0=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D1=82=D0=B5=D0=B3=D1=83.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/ncui/engine/action.d | 30 +++++++++++++++++++------- source/ncui/engine/ncui.d | 42 +++++++++++++++++++++++++++++++++++++ source/ncui/engine/screen.d | 6 ++++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/source/ncui/engine/action.d b/source/ncui/engine/action.d index 7362228..10925df 100644 --- a/source/ncui/engine/action.d +++ b/source/ncui/engine/action.d @@ -21,6 +21,8 @@ enum ActionKind Replace, // Удалить один или несколько экранов с вершины стека. Pop, + // Удалить один или несколько экранов с вершины стека до указанного тега. + PopTo, // Завершить выполнение UI-цикла. Quit } @@ -66,8 +68,10 @@ struct ScreenAction IScreen next; // Результат (используется для `Pop`, `Quit`). ScreenResult result; - // Количество извлекаемых экранов. + // Количество удаляемых экранов. int popScreenCount; + // Целевой тег экрана, до которого необходимо удалить экраны из стека. + int targetTag; /** * Ничего не делать. @@ -76,7 +80,7 @@ struct ScreenAction */ static ScreenAction none() { - return ScreenAction(ActionKind.None, null, ScreenResult.none(), 0); + return ScreenAction(ActionKind.None, null, ScreenResult.none(), 0, 0); } /** @@ -88,7 +92,7 @@ struct ScreenAction static ScreenAction push(IScreen screen) { // assert(isPointer!(typeof(result)), "ncuiNotNull expects a function that returns a pointer."); - return ScreenAction(ActionKind.Push, screen, ScreenResult.none(), 0); + return ScreenAction(ActionKind.Push, screen, ScreenResult.none(), 0, 0); } /** @@ -99,7 +103,7 @@ struct ScreenAction */ static ScreenAction replace(IScreen screen) { - return ScreenAction(ActionKind.Replace, screen, ScreenResult.none(), 0); + return ScreenAction(ActionKind.Replace, screen, ScreenResult.none(), 0, 0); } /** @@ -110,7 +114,7 @@ struct ScreenAction */ static ScreenAction pop(ScreenResult result) { - return ScreenAction(ActionKind.Pop, null, result, 1); + return ScreenAction(ActionKind.Pop, null, result, 1, 0); } /** @@ -121,7 +125,19 @@ struct ScreenAction */ static ScreenAction popN(int count, ScreenResult result) { - return ScreenAction(ActionKind.Pop, null, result, count < 1 ? 1 : count); + return ScreenAction(ActionKind.Pop, null, result, count < 1 ? 1 : count, 0); + } + + /** + * Закрыть экраны до экрана с указанным тегом и передать ему результат. + * + * Params: + * - tag: целевой тег. + * - result: результат закрываемого экрана. + */ + static ScreenAction popTo(int targetTag, ScreenResult result) + { + return ScreenAction(ActionKind.PopTo, null, result, 0, targetTag); } /** @@ -132,6 +148,6 @@ struct ScreenAction */ static ScreenAction quit(ScreenResult result) { - return ScreenAction(ActionKind.Quit, null, result, 0); + return ScreenAction(ActionKind.Quit, null, result, 0, 0); } } diff --git a/source/ncui/engine/ncui.d b/source/ncui/engine/ncui.d index b43e097..afc84c4 100644 --- a/source/ncui/engine/ncui.d +++ b/source/ncui/engine/ncui.d @@ -38,6 +38,24 @@ private: } } + // Проверить наличие тега у экрана. + int hasScreenTag(IScreen screen) + { + auto taggetScreen = cast(ITaggedScreen) screen; + // Пользовательский тег не должен быть равен int.min! + return (taggetScreen is null) ? int.min : taggetScreen.tag(); + } + + // Извлечение из стека экраны до указанного тега. + void popToTag(int targetTag) + { + while (_stack.length != 0 && hasScreenTag(_stack[$ - 1]) != targetTag) + { + _stack[$ - 1].close(); + _stack.popBack(); + } + } + void apply(ScreenAction action) { while (_running && action.kind != ActionKind.None) @@ -86,6 +104,30 @@ private: action = parent.onShow(_context); break; + case ActionKind.PopTo: + // Результат работы удаляемого экрана (дочерний экран). + // Позже он будет передан родительскому экрану. + auto childResult = action.result; + // Удалить экраны до указанного тега. + popToTag(action.targetTag); + _session.clear(); + if (_stack.length == 0) + { + _result = childResult; + _running = false; + return; + } + auto parent = _stack[$ - 1]; + // Передача результата дочернего экрана первому экрану в стеке (родительскому экрану). + auto actionResult = parent.onChildResult(_context, childResult); + if (actionResult.kind != ActionKind.None) + { + action = actionResult; + break; + } + action = parent.onShow(_context); + break; + case ActionKind.Quit: _result = action.result; _running = false; diff --git a/source/ncui/engine/screen.d b/source/ncui/engine/screen.d index 400271c..456941f 100644 --- a/source/ncui/engine/screen.d +++ b/source/ncui/engine/screen.d @@ -51,6 +51,12 @@ interface IScreen void close(); } +// Интерфейс тега экрана. +interface ITaggedScreen +{ + int tag(); +} + abstract class ScreenBase : IScreen { protected: