Добавлена возможность удаления экрана по тегу.

This commit is contained in:
Alexander Zhirov 2026-01-07 17:20:47 +03:00
parent 1a3c144e80
commit 42744c6b16
Signed by: alexander
GPG key ID: C8D8BE544A27C511
3 changed files with 71 additions and 7 deletions

View file

@ -21,6 +21,8 @@ enum ActionKind
Replace, Replace,
// Удалить один или несколько экранов с вершины стека. // Удалить один или несколько экранов с вершины стека.
Pop, Pop,
// Удалить один или несколько экранов с вершины стека до указанного тега.
PopTo,
// Завершить выполнение UI-цикла. // Завершить выполнение UI-цикла.
Quit Quit
} }
@ -66,8 +68,10 @@ struct ScreenAction
IScreen next; IScreen next;
// Результат (используется для `Pop`, `Quit`). // Результат (используется для `Pop`, `Quit`).
ScreenResult result; ScreenResult result;
// Количество извлекаемых экранов. // Количество удаляемых экранов.
int popScreenCount; int popScreenCount;
// Целевой тег экрана, до которого необходимо удалить экраны из стека.
int targetTag;
/** /**
* Ничего не делать. * Ничего не делать.
@ -76,7 +80,7 @@ struct ScreenAction
*/ */
static ScreenAction none() 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) static ScreenAction push(IScreen screen)
{ {
// assert(isPointer!(typeof(result)), "ncuiNotNull expects a function that returns a pointer."); // 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) 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) 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) 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) static ScreenAction quit(ScreenResult result)
{ {
return ScreenAction(ActionKind.Quit, null, result, 0); return ScreenAction(ActionKind.Quit, null, result, 0, 0);
} }
} }

View file

@ -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) void apply(ScreenAction action)
{ {
while (_running && action.kind != ActionKind.None) while (_running && action.kind != ActionKind.None)
@ -86,6 +104,30 @@ private:
action = parent.onShow(_context); action = parent.onShow(_context);
break; 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: case ActionKind.Quit:
_result = action.result; _result = action.result;
_running = false; _running = false;

View file

@ -51,6 +51,12 @@ interface IScreen
void close(); void close();
} }
// Интерфейс тега экрана.
interface ITaggedScreen
{
int tag();
}
abstract class ScreenBase : IScreen abstract class ScreenBase : IScreen
{ {
protected: protected: