simpleui-py 1.2.2__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {simpleui_py-1.2.2/simpleui_py.egg-info → simpleui_py-1.3.0}/PKG-INFO +3 -2
  2. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/README.md +2 -1
  3. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/pyproject.toml +1 -1
  4. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/__init__.py +9 -13
  5. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/components/__init__.py +3 -3
  6. simpleui_py-1.3.0/simpleui/components/button.py +105 -0
  7. simpleui_py-1.3.0/simpleui/components/input.py +85 -0
  8. simpleui_py-1.3.0/simpleui/components/layout.py +57 -0
  9. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/components/window.py +113 -23
  10. simpleui_py-1.3.0/simpleui/core.py +118 -0
  11. simpleui_py-1.3.0/simpleui/icons.py +100 -0
  12. simpleui_py-1.3.0/simpleui/stage.py +245 -0
  13. {simpleui_py-1.2.2 → simpleui_py-1.3.0/simpleui_py.egg-info}/PKG-INFO +3 -2
  14. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui_py.egg-info/SOURCES.txt +2 -0
  15. simpleui_py-1.2.2/simpleui/components/button.py +0 -259
  16. simpleui_py-1.2.2/simpleui/components/input.py +0 -264
  17. simpleui_py-1.2.2/simpleui/components/layout.py +0 -174
  18. simpleui_py-1.2.2/simpleui/core.py +0 -1177
  19. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/LICENSE +0 -0
  20. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/MANIFEST.in +0 -0
  21. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/setup.cfg +0 -0
  22. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/components/alert.py +0 -0
  23. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/components/card.py +0 -0
  24. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/components/progress.py +0 -0
  25. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/components/switch.py +0 -0
  26. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/components/tag.py +0 -0
  27. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/py.typed +0 -0
  28. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui/utils.py +0 -0
  29. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui_py.egg-info/dependency_links.txt +0 -0
  30. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui_py.egg-info/entry_points.txt +0 -0
  31. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui_py.egg-info/requires.txt +0 -0
  32. {simpleui_py-1.2.2 → simpleui_py-1.3.0}/simpleui_py.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simpleui-py
3
- Version: 1.2.2
3
+ Version: 1.3.0
4
4
  Summary: Fluent风格Python UI组件库 - 简约设计,无限可能
5
5
  Author-email: SimpleUI Team <hello@simpleui.dev>
6
6
  License: MIT
@@ -46,7 +46,8 @@ Dynamic: license-file
46
46
 
47
47
 
48
48
 
49
- \## 安装
49
+ \## 安装:pip install simpleui=={版本} 引用:from simpleui import {内容}
50
+
50
51
 
51
52
 
52
53
 
@@ -22,7 +22,8 @@
22
22
 
23
23
 
24
24
 
25
- \## 安装
25
+ \## 安装:pip install simpleui=={版本} 引用:from simpleui import {内容}
26
+
26
27
 
27
28
 
28
29
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simpleui-py"
7
- version = "1.2.2"
7
+ version = "1.3.0"
8
8
  description = "Fluent风格Python UI组件库 - 简约设计,无限可能"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,12 +1,10 @@
1
1
  """
2
2
  SimpleUI - Fluent 风格 Python UI 组件库
3
- 简约设计,无限可能
4
3
  """
5
4
 
6
- __version__ = "1.2.2"
5
+ __version__ = "1.3.0"
7
6
  __author__ = "SimpleUI Team"
8
7
 
9
- # 从 core 导入核心功能
10
8
  from .core import (
11
9
  Component,
12
10
  Theme,
@@ -17,7 +15,6 @@ from .core import (
17
15
  get_theme,
18
16
  )
19
17
 
20
- # 从 components 导入所有组件
21
18
  from .components import (
22
19
  Button,
23
20
  ButtonGroup,
@@ -31,18 +28,17 @@ from .components import (
31
28
  Container,
32
29
  Row,
33
30
  Column,
31
+ Window,
32
+ WindowManager,
34
33
  )
35
34
 
36
- # utils 导入工具函数
35
+ from .stage import Stage, Sprite # 新增
36
+
37
37
  from .utils import preview, serve, demo, playground
38
38
 
39
- # 导出列表
40
39
  __all__ = [
41
- # 版本信息
42
40
  "__version__",
43
41
  "__author__",
44
-
45
- # 核心类
46
42
  "Component",
47
43
  "Theme",
48
44
  "ThemeType",
@@ -50,8 +46,6 @@ __all__ = [
50
46
  "export_html",
51
47
  "set_theme",
52
48
  "get_theme",
53
-
54
- # 组件
55
49
  "Button",
56
50
  "ButtonGroup",
57
51
  "Input",
@@ -64,8 +58,10 @@ __all__ = [
64
58
  "Container",
65
59
  "Row",
66
60
  "Column",
67
-
68
- # 工具函数
61
+ "Window",
62
+ "WindowManager",
63
+ "Stage", # 新增
64
+ "Sprite", # 新增
69
65
  "preview",
70
66
  "serve",
71
67
  "demo",
@@ -10,7 +10,7 @@ from .tag import Tag
10
10
  from .progress import Progress
11
11
  from .alert import Alert
12
12
  from .layout import Container, Row, Column
13
- from .window import Window, WindowManager # 新增
13
+ from .window import Window, WindowManager
14
14
 
15
15
  __all__ = [
16
16
  "Button",
@@ -25,6 +25,6 @@ __all__ = [
25
25
  "Container",
26
26
  "Row",
27
27
  "Column",
28
- "Window", # 新增
29
- "WindowManager", # 新增
28
+ "Window",
29
+ "WindowManager",
30
30
  ]
@@ -0,0 +1,105 @@
1
+ """按钮组件"""
2
+ from typing import Optional, Literal
3
+ from ..core import Component
4
+ from ..icons import get_icon
5
+
6
+
7
+ class Button(Component):
8
+ """按钮组件"""
9
+
10
+ VARIANT_CLASSES = {
11
+ "primary": "sui-btn-primary",
12
+ "secondary": "sui-btn-secondary",
13
+ "outline": "sui-btn-outline",
14
+ "ghost": "sui-btn-ghost",
15
+ "danger": "sui-btn-danger",
16
+ "success": "sui-btn-success",
17
+ }
18
+
19
+ SIZE_CLASSES = {
20
+ "sm": "sui-btn-sm",
21
+ "md": "",
22
+ "lg": "sui-btn-lg",
23
+ }
24
+
25
+ def __init__(
26
+ self,
27
+ text: Optional[str] = None,
28
+ variant: str = "primary",
29
+ size: str = "md",
30
+ icon: Optional[str] = None,
31
+ icon_position: str = "left",
32
+ loading: bool = False,
33
+ disabled: bool = False,
34
+ href: Optional[str] = None,
35
+ onclick: Optional[str] = None,
36
+ **kwargs
37
+ ):
38
+ super().__init__(**kwargs)
39
+ self.text = text
40
+ self.variant = variant
41
+ self.size = size
42
+ self.icon = icon
43
+ self.icon_position = icon_position
44
+ self.loading = loading
45
+ self.disabled = disabled
46
+ self.href = href
47
+ self.onclick = onclick
48
+
49
+ def _get_base_classes(self) -> str:
50
+ classes = ["sui-btn", self.VARIANT_CLASSES.get(self.variant, ""), self.SIZE_CLASSES.get(self.size, "")]
51
+ if self.loading:
52
+ classes.append("sui-btn-loading")
53
+ if self.class_name:
54
+ classes.append(self.class_name)
55
+ return " ".join(classes)
56
+
57
+ def _get_attributes_str(self) -> str:
58
+ attrs = super()._get_attributes_str()
59
+ if self.disabled or self.loading:
60
+ attrs += " disabled"
61
+ if self.onclick and not self.disabled:
62
+ attrs += f' onclick="{self.onclick}"'
63
+ return attrs
64
+
65
+ def _render_icon(self) -> str:
66
+ if not self.icon:
67
+ return ""
68
+
69
+ icon_path = get_icon(self.icon)
70
+ if not icon_path:
71
+ return ""
72
+
73
+ icon_html = f'<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16">{icon_path}</svg>'
74
+
75
+ if self.icon_position == "right":
76
+ return f'<span>{self.text or ""}</span>{icon_html}'
77
+ return f'{icon_html}<span>{self.text or ""}</span>'
78
+
79
+ def render(self) -> str:
80
+ content = self._render_icon() if self.icon else (self.text or "")
81
+ content += self._render_children()
82
+
83
+ if self.href:
84
+ return f'<a href="{self.href}" {self._get_attributes_str()}>{content}</a>'
85
+ return f'<button {self._get_attributes_str()}>{content}</button>'
86
+
87
+ @classmethod
88
+ def icon_button(cls, icon: str, variant: str = "primary", size: str = "md", **kwargs) -> "Button":
89
+ """创建图标按钮"""
90
+ return cls(variant=variant, size=size, icon=icon, class_name="sui-btn-icon " + kwargs.pop("class_name", ""), **kwargs)
91
+
92
+
93
+ class ButtonGroup(Component):
94
+ """按钮组"""
95
+
96
+ def __init__(self, *buttons, **kwargs):
97
+ super().__init__(**kwargs)
98
+ for btn in buttons:
99
+ self.add_child(btn)
100
+
101
+ def _get_base_classes(self) -> str:
102
+ return f"sui-btn-group {self.class_name}".strip()
103
+
104
+ def render(self) -> str:
105
+ return f'<div {self._get_attributes_str()}>{self._render_children()}</div>'
@@ -0,0 +1,85 @@
1
+ """输入框组件"""
2
+ from typing import Optional, Literal
3
+ from ..core import Component
4
+ from ..icons import get_icon
5
+
6
+
7
+ class Input(Component):
8
+ """输入框组件"""
9
+
10
+ STATUS_CLASSES = {"default": "", "success": "sui-input-success", "error": "sui-input-error"}
11
+
12
+ def __init__(
13
+ self,
14
+ label: Optional[str] = None,
15
+ placeholder: Optional[str] = None,
16
+ value: Optional[str] = None,
17
+ type: str = "text",
18
+ status: str = "default",
19
+ helper_text: Optional[str] = None,
20
+ icon: Optional[str] = None, # 直接使用图标名
21
+ disabled: bool = False,
22
+ required: bool = False,
23
+ **kwargs
24
+ ):
25
+ super().__init__(**kwargs)
26
+ self.label = label
27
+ self.placeholder = placeholder
28
+ self.value = value
29
+ self.type = type
30
+ self.status = status
31
+ self.helper_text = helper_text
32
+ self.icon = icon
33
+ self.disabled = disabled
34
+ self.required = required
35
+
36
+ def render(self) -> str:
37
+ html = ['<div class="sui-input-wrapper">']
38
+
39
+ if self.label:
40
+ html.append(f'<label class="sui-input-label">{self.label}{" *" if self.required else ""}</label>')
41
+
42
+ input_class = f"sui-input {self.STATUS_CLASSES.get(self.status, '')}".strip()
43
+ attrs = [f'type="{self.type}"', f'class="{input_class}"']
44
+
45
+ if self.placeholder:
46
+ attrs.append(f'placeholder="{self.placeholder}"')
47
+ if self.value:
48
+ attrs.append(f'value="{self.value}"')
49
+ if self.disabled:
50
+ attrs.append("disabled")
51
+ if self.required:
52
+ attrs.append("required")
53
+
54
+ if self.icon:
55
+ icon_path = get_icon(self.icon)
56
+ html.append('<div class="sui-input-icon-wrapper">')
57
+ html.append(f'<span class="sui-input-icon"><svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18">{icon_path}</svg></span>')
58
+ html.append(f'<input {" ".join(attrs)}>')
59
+ html.append('</div>')
60
+ else:
61
+ html.append(f'<input {" ".join(attrs)}>')
62
+
63
+ if self.helper_text:
64
+ h_class = "sui-input-helper" + (" sui-input-error-text" if self.status == "error" else "")
65
+ html.append(f'<span class="{h_class}">{self.helper_text}</span>')
66
+
67
+ html.append('</div>')
68
+ return "".join(html)
69
+
70
+
71
+ class TextArea(Component):
72
+ """多行文本"""
73
+
74
+ def __init__(self, label: Optional[str] = None, placeholder: Optional[str] = None, rows: int = 4, **kwargs):
75
+ super().__init__(**kwargs)
76
+ self.label = label
77
+ self.placeholder = placeholder
78
+ self.rows = rows
79
+
80
+ def render(self) -> str:
81
+ html = ['<div class="sui-input-wrapper">']
82
+ if self.label:
83
+ html.append(f'<label class="sui-input-label">{self.label}</label>')
84
+ html.append(f'<textarea class="sui-input sui-textarea" rows="{self.rows}" placeholder="{self.placeholder or ""}"></textarea></div>')
85
+ return "".join(html)
@@ -0,0 +1,57 @@
1
+ """布局组件"""
2
+ from typing import Union
3
+ from ..core import Component
4
+
5
+
6
+ class Container(Component):
7
+ """容器"""
8
+
9
+ def __init__(self, *children, max_width: str = "1200px", **kwargs):
10
+ super().__init__(**kwargs)
11
+ self.max_width = max_width
12
+ for child in children:
13
+ self.add_child(child)
14
+
15
+ def _get_style_str(self) -> str:
16
+ return f"max-width:{self.max_width};margin:0 auto;padding:2rem"
17
+
18
+ def render(self) -> str:
19
+ return f'<div class="sui-container" style="{self._get_style_str()}">{self._render_children()}</div>'
20
+
21
+
22
+ class Row(Component):
23
+ """行布局"""
24
+
25
+ ALIGN = {"start": "flex-start", "center": "center", "end": "flex-end"}
26
+ JUSTIFY = {"start": "flex-start", "center": "center", "end": "flex-end", "between": "space-between",
27
+ "around": "space-around"}
28
+
29
+ def __init__(self, *children, gap: str = "1rem", justify: str = "start", align: str = "center", **kwargs):
30
+ super().__init__(**kwargs)
31
+ self.gap = gap
32
+ self.justify = justify
33
+ self.align = align
34
+ for child in children:
35
+ self.add_child(child)
36
+
37
+ def _get_style_str(self) -> str:
38
+ return f"display:flex;flex-wrap:wrap;gap:{self.gap};justify-content:{self.JUSTIFY.get(self.justify, self.justify)};align-items:{self.ALIGN.get(self.align, self.align)}"
39
+
40
+ def render(self) -> str:
41
+ return f'<div class="sui-row" style="{self._get_style_str()}">{self._render_children()}</div>'
42
+
43
+
44
+ class Column(Component):
45
+ """列布局"""
46
+
47
+ def __init__(self, *children, flex: int = 1, **kwargs):
48
+ super().__init__(**kwargs)
49
+ self.flex = flex
50
+ for child in children:
51
+ self.add_child(child)
52
+
53
+ def _get_style_str(self) -> str:
54
+ return f"flex:{self.flex};min-width:200px"
55
+
56
+ def render(self) -> str:
57
+ return f'<div class="sui-column" style="{self._get_style_str()}">{self._render_children()}</div>'
@@ -1,6 +1,6 @@
1
1
  """
2
2
  窗口组件
3
- 可拖动的窗口,支持子组件随窗口移动
3
+ 可拖动的窗口,使用 TurboWarp 坐标系
4
4
  """
5
5
 
6
6
  from typing import Optional, List, Union
@@ -11,12 +11,19 @@ class Window(Component):
11
11
  """
12
12
  可拖动窗口组件
13
13
 
14
+ 使用 TurboWarp 坐标系:
15
+ - 原点在舞台中心
16
+ - X轴:右为正,左为负
17
+ - Y轴:上为正,下为负
18
+
14
19
  参数:
15
20
  title: 窗口标题
16
21
  width: 窗口宽度
17
22
  height: 窗口高度
18
- x: 初始X坐标
19
- y: 初始Y坐标
23
+ x: X坐标(中心为0,右为正)
24
+ y: Y坐标(中心为0,上为正)
25
+ stage_width: 舞台宽度
26
+ stage_height: 舞台高度
20
27
  draggable: 是否可拖动
21
28
  resizable: 是否可调整大小
22
29
  closable: 是否可关闭
@@ -25,7 +32,7 @@ class Window(Component):
25
32
  fixed_child: 子组件是否随窗口移动
26
33
 
27
34
  示例:
28
- win = Window(title="我的窗口", x=100, y=100)
35
+ win = Window(title="窗口", x=100, y=100)
29
36
  win.add_child(Button("按钮", variant="primary"))
30
37
  preview(win)
31
38
  """
@@ -35,30 +42,93 @@ class Window(Component):
35
42
  title: str = "窗口",
36
43
  width: str = "400px",
37
44
  height: str = "300px",
38
- x: int = 100,
39
- y: int = 100,
45
+ x: int = 0,
46
+ y: int = 0,
47
+ stage_width: int = 800,
48
+ stage_height: int = 600,
40
49
  draggable: bool = True,
41
50
  resizable: bool = True,
42
51
  closable: bool = True,
43
52
  minimize: bool = True,
44
53
  header: bool = True,
45
- fixed_child: bool = True, # 改这里
54
+ fixed_child: bool = True,
46
55
  **kwargs
47
56
  ):
48
57
  super().__init__(**kwargs)
49
58
  self.title = title
50
59
  self.width = width
51
60
  self.height = height
52
- self.x = x
53
- self.y = y
61
+ self._x = x
62
+ self._y = y
63
+ self.stage_width = stage_width
64
+ self.stage_height = stage_height
54
65
  self.draggable = draggable
55
66
  self.resizable = resizable
56
67
  self.closable = closable
57
68
  self.minimize = minimize
58
69
  self.header = header
59
- self.fixed_child = fixed_child # 改这里
70
+ self.fixed_child = fixed_child
60
71
  self._children: List[Union[Component, str]] = []
61
72
  self._minimized = False
73
+
74
+ # 计算中心点
75
+ self._center_x = stage_width // 2
76
+ self._center_y = stage_height // 2
77
+
78
+ @property
79
+ def x(self) -> int:
80
+ """获取 X 坐标"""
81
+ return self._x
82
+
83
+ @x.setter
84
+ def x(self, value: int):
85
+ """设置 X 坐标"""
86
+ self._x = value
87
+
88
+ @property
89
+ def y(self) -> int:
90
+ """获取 Y 坐标"""
91
+ return self._y
92
+
93
+ @y.setter
94
+ def y(self, value: int):
95
+ """设置 Y 坐标"""
96
+ self._y = value
97
+
98
+ def to_screen_coords(self) -> tuple:
99
+ """
100
+ 将 TurboWarp 坐标转换为屏幕坐标
101
+
102
+ 返回:
103
+ (screen_x, screen_y) 屏幕坐标
104
+ """
105
+ screen_x = self._center_x + self._x
106
+ screen_y = self._center_y - self._y # Y轴反转
107
+ return int(screen_x), int(screen_y)
108
+
109
+ def move(self, dx: int, dy: int) -> 'Window':
110
+ """
111
+ 移动窗口
112
+
113
+ 参数:
114
+ dx: X方向移动量(右为正)
115
+ dy: Y方向移动量(上为正)
116
+ """
117
+ self._x += dx
118
+ self._y += dy
119
+ return self
120
+
121
+ def goto(self, x: int, y: int) -> 'Window':
122
+ """
123
+ 移动到指定位置
124
+
125
+ 参数:
126
+ x: X坐标
127
+ y: Y坐标
128
+ """
129
+ self._x = x
130
+ self._y = y
131
+ return self
62
132
 
63
133
  def add_child(self, child: Union[Component, str]) -> 'Window':
64
134
  """添加子组件"""
@@ -80,12 +150,15 @@ class Window(Component):
80
150
 
81
151
  def render(self) -> str:
82
152
  """渲染窗口"""
153
+ # 转换坐标
154
+ screen_x, screen_y = self.to_screen_coords()
155
+
83
156
  # 窗口样式
84
157
  window_style = f"""
85
158
  width: {self.width};
86
159
  height: {self.height};
87
- left: {self.x}px;
88
- top: {self.y}px;
160
+ left: {screen_x}px;
161
+ top: {screen_y}px;
89
162
  """
90
163
 
91
164
  # 标题栏按钮
@@ -101,11 +174,14 @@ class Window(Component):
101
174
  # 调整大小
102
175
  resize_handle = '<div class="sui-window-resize"></div>' if self.resizable else ''
103
176
 
104
- # 子组件容器 - 改这里
177
+ # 子组件容器
105
178
  children_class = "sui-window-content" if self.fixed_child else "sui-window-content-absolute"
106
179
 
180
+ # 存储坐标信息
181
+ data_attrs = f'data-x="{self._x}" data-y="{self._y}" data-stage-width="{self.stage_width}" data-stage-height="{self.stage_height}"'
182
+
107
183
  html = f'''
108
- <div class="{self._get_base_classes()}" style="{window_style}" {drag_attr}>
184
+ <div class="{self._get_base_classes()}" style="{window_style}" {drag_attr} {data_attrs}>
109
185
  <!-- 标题栏 -->
110
186
  {'<div class="sui-window-header">' if self.header else '<div class="sui-window-header" style="display:none">'}
111
187
  <span class="sui-window-title">{self.title}</span>
@@ -129,26 +205,40 @@ class Window(Component):
129
205
  class WindowManager:
130
206
  """
131
207
  窗口管理器
132
- 用于管理多个窗口
133
208
 
134
- 示例:
135
- wm = WindowManager()
136
- wm.add_window(Window(title="窗口1"))
137
- wm.add_window(Window(title="窗口2"))
138
- preview(wm)
209
+ 参数:
210
+ stage_width: 舞台宽度
211
+ stage_height: 舞台高度
139
212
  """
140
213
 
141
- def __init__(self):
214
+ def __init__(
215
+ self,
216
+ stage_width: int = 800,
217
+ stage_height: int = 600
218
+ ):
142
219
  self.windows: List[Window] = []
220
+ self.stage_width = stage_width
221
+ self.stage_height = stage_height
143
222
 
144
223
  def add_window(self, window: Window) -> 'WindowManager':
145
224
  """添加窗口"""
146
225
  self.windows.append(window)
147
226
  return self
148
227
 
149
- def create_window(self, title: str = "窗口", **kwargs) -> Window:
228
+ def create_window(
229
+ self,
230
+ title: str = "窗口",
231
+ x: int = 0,
232
+ y: int = 0,
233
+ **kwargs
234
+ ) -> Window:
150
235
  """创建并添加窗口"""
151
- win = Window(title=title, **kwargs)
236
+ if 'stage_width' not in kwargs:
237
+ kwargs['stage_width'] = self.stage_width
238
+ if 'stage_height' not in kwargs:
239
+ kwargs['stage_height'] = self.stage_height
240
+
241
+ win = Window(title=title, x=x, y=y, **kwargs)
152
242
  self.windows.append(win)
153
243
  return win
154
244