dex-framework 0.0.50__py3-none-any.whl
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.
- dex_framework/__init__.py +22 -0
- dex_framework/buttons/DEx_ActionButtons.py +212 -0
- dex_framework/buttons/DEx_CupertinoButton.py +52 -0
- dex_framework/buttons/DEx_CupertinoFilledButton.py +52 -0
- dex_framework/buttons/DEx_ElevatedButton.py +57 -0
- dex_framework/buttons/DEx_FilledButton.py +52 -0
- dex_framework/buttons/DEx_FilledTonalButton.py +52 -0
- dex_framework/buttons/DEx_FloatingActionButton.py +52 -0
- dex_framework/buttons/DEx_IconButton.py +52 -0
- dex_framework/buttons/DEx_MenuItemButton.py +52 -0
- dex_framework/buttons/DEx_OutlinedButton.py +52 -0
- dex_framework/buttons/DEx_PopupMenuButton.py +52 -0
- dex_framework/buttons/DEx_SubmenuButton.py +52 -0
- dex_framework/buttons/DEx_TextButton.py +52 -0
- dex_framework/buttons/__init__.py +30 -0
- dex_framework/canvas/DEx_Canvas.py +50 -0
- dex_framework/canvas/__init__.py +3 -0
- dex_framework/charts/DEx_BarChart.py +82 -0
- dex_framework/charts/DEx_CandlestickChart.py +288 -0
- dex_framework/charts/DEx_DonutChart.py +334 -0
- dex_framework/charts/DEx_GeoHeatmap.py +305 -0
- dex_framework/charts/DEx_HeatmapChart.py +363 -0
- dex_framework/charts/DEx_LineChart.py +85 -0
- dex_framework/charts/DEx_PieChart.py +79 -0
- dex_framework/charts/__init__.py +15 -0
- dex_framework/charts/_brazil_states.py +295 -0
- dex_framework/core/DEx_Compat.py +45 -0
- dex_framework/core/DEx_Config.py +26 -0
- dex_framework/core/DEx_Protocol.py +30 -0
- dex_framework/core/__init__.py +13 -0
- dex_framework/display/DEx_Card.py +50 -0
- dex_framework/display/DEx_CircleAvatar.py +50 -0
- dex_framework/display/DEx_DataTable.py +50 -0
- dex_framework/display/DEx_ExpansionPanel.py +50 -0
- dex_framework/display/DEx_ExpansionTile.py +50 -0
- dex_framework/display/DEx_GridView.py +50 -0
- dex_framework/display/DEx_Icon.py +50 -0
- dex_framework/display/DEx_Image.py +50 -0
- dex_framework/display/DEx_KpiCard.py +205 -0
- dex_framework/display/DEx_ListTile.py +50 -0
- dex_framework/display/DEx_ListView.py +50 -0
- dex_framework/display/DEx_Markdown.py +50 -0
- dex_framework/display/DEx_Text.py +50 -0
- dex_framework/display/DEx_VersionBar.py +80 -0
- dex_framework/display/__init__.py +21 -0
- dex_framework/feedback/DEx_AlertDialog.py +50 -0
- dex_framework/feedback/DEx_Badge.py +50 -0
- dex_framework/feedback/DEx_Banner.py +50 -0
- dex_framework/feedback/DEx_Chip.py +50 -0
- dex_framework/feedback/DEx_CupertinoActivityIndicator.py +50 -0
- dex_framework/feedback/DEx_CupertinoAlertDialog.py +50 -0
- dex_framework/feedback/DEx_ProgressBar.py +50 -0
- dex_framework/feedback/DEx_ProgressRing.py +50 -0
- dex_framework/feedback/DEx_SnackBar.py +50 -0
- dex_framework/feedback/DEx_Tooltip.py +53 -0
- dex_framework/feedback/__init__.py +17 -0
- dex_framework/input/DEx_Checkbox.py +50 -0
- dex_framework/input/DEx_CupertinoCheckbox.py +50 -0
- dex_framework/input/DEx_CupertinoSlider.py +50 -0
- dex_framework/input/DEx_CupertinoSwitch.py +50 -0
- dex_framework/input/DEx_CupertinoTextField.py +56 -0
- dex_framework/input/DEx_DatePicker.py +50 -0
- dex_framework/input/DEx_Dropdown.py +57 -0
- dex_framework/input/DEx_Radio.py +50 -0
- dex_framework/input/DEx_RadioGroup.py +50 -0
- dex_framework/input/DEx_RangeSlider.py +50 -0
- dex_framework/input/DEx_Slider.py +50 -0
- dex_framework/input/DEx_Switch.py +50 -0
- dex_framework/input/DEx_TextField.py +57 -0
- dex_framework/input/DEx_TimePicker.py +50 -0
- dex_framework/input/__init__.py +22 -0
- dex_framework/interaction/DEx_Dismissible.py +50 -0
- dex_framework/interaction/DEx_Draggable.py +50 -0
- dex_framework/interaction/DEx_GestureDetector.py +50 -0
- dex_framework/interaction/DEx_SelectionArea.py +50 -0
- dex_framework/interaction/DEx_TransparentPointer.py +50 -0
- dex_framework/interaction/__init__.py +10 -0
- dex_framework/layout/DEx_AppShell.py +394 -0
- dex_framework/layout/DEx_Column.py +50 -0
- dex_framework/layout/DEx_Container.py +50 -0
- dex_framework/layout/DEx_Header.py +171 -0
- dex_framework/layout/DEx_ResponsiveRow.py +50 -0
- dex_framework/layout/DEx_Row.py +50 -0
- dex_framework/layout/DEx_SafeArea.py +50 -0
- dex_framework/layout/DEx_Stack.py +50 -0
- dex_framework/layout/__init__.py +15 -0
- dex_framework/maps/DEx_GeoHeatmap.py +703 -0
- dex_framework/maps/DEx_Map.py +79 -0
- dex_framework/maps/__init__.py +4 -0
- dex_framework/media/DEx_Audio.py +80 -0
- dex_framework/media/DEx_Lottie.py +82 -0
- dex_framework/media/DEx_Video.py +75 -0
- dex_framework/media/__init__.py +5 -0
- dex_framework/navigation/DEx_AppBar.py +50 -0
- dex_framework/navigation/DEx_CupertinoNavigationBar.py +50 -0
- dex_framework/navigation/DEx_NavBar.py +531 -0
- dex_framework/navigation/DEx_NavigationBar.py +50 -0
- dex_framework/navigation/DEx_NavigationDrawer.py +50 -0
- dex_framework/navigation/DEx_NavigationRail.py +50 -0
- dex_framework/navigation/DEx_Tabs.py +158 -0
- dex_framework/navigation/__init__.py +13 -0
- dex_framework/overlay/DEx_BottomSheet.py +50 -0
- dex_framework/overlay/DEx_CupertinoBottomSheet.py +50 -0
- dex_framework/overlay/DEx_Drawer.py +51 -0
- dex_framework/overlay/DEx_MenuBar.py +50 -0
- dex_framework/overlay/DEx_Pagelet.py +50 -0
- dex_framework/overlay/DEx_SearchAnchor.py +67 -0
- dex_framework/overlay/DEx_SearchBar.py +50 -0
- dex_framework/overlay/__init__.py +12 -0
- dex_framework/py.typed +0 -0
- dex_framework/scrolling/DEx_DragTarget.py +50 -0
- dex_framework/scrolling/DEx_ScrollableControl.py +56 -0
- dex_framework/scrolling/__init__.py +4 -0
- dex_framework/theming/DEx_BrandThemes.py +1006 -0
- dex_framework/theming/DEx_ColorScheme.py +37 -0
- dex_framework/theming/DEx_Theme.py +37 -0
- dex_framework/theming/__init__.py +5 -0
- dex_framework-0.0.50.dist-info/METADATA +217 -0
- dex_framework-0.0.50.dist-info/RECORD +122 -0
- dex_framework-0.0.50.dist-info/WHEEL +5 -0
- dex_framework-0.0.50.dist-info/licenses/LICENSE +21 -0
- dex_framework-0.0.50.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DEx_OutlinedButton — DEx-Framework v3.0.0
|
|
3
|
+
Encapsula flet.OutlinedButton com padrões DEx.
|
|
4
|
+
|
|
5
|
+
Uso básico:
|
|
6
|
+
from dex_framework.buttons import DEx_OutlinedButton
|
|
7
|
+
componente = DEx_OutlinedButton(...)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
import flet as ft
|
|
12
|
+
from typing import Any, Callable, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DEx_OutlinedButton(ft.OutlinedButton):
|
|
16
|
+
"""
|
|
17
|
+
Encapsulamento DEx do controle flet.OutlinedButton.
|
|
18
|
+
|
|
19
|
+
Mantém 100% da API original do Flet e adiciona:
|
|
20
|
+
- Valores padrão opinados (brand defaults)
|
|
21
|
+
- Parâmetro `dex_id` para rastreamento
|
|
22
|
+
- Hook `on_dex_ready` disparado após montagem
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
dex_id: Identificador único do componente na aplicação.
|
|
26
|
+
on_dex_ready: Callback chamado quando o componente é montado.
|
|
27
|
+
**kwargs: Todos os parâmetros nativos de flet.OutlinedButton.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
>>> btn = DEx_OutlinedButton(
|
|
31
|
+
... dex_id="exemplo",
|
|
32
|
+
... )
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
*args: Any,
|
|
38
|
+
dex_id: str = "",
|
|
39
|
+
dex_theme: str = "dell",
|
|
40
|
+
on_dex_ready: Optional[Callable[["DEx_OutlinedButton"], None]] = None,
|
|
41
|
+
**kwargs: Any,
|
|
42
|
+
) -> None:
|
|
43
|
+
super().__init__(*args, **kwargs)
|
|
44
|
+
self.dex_id: str = dex_id
|
|
45
|
+
self.dex_theme: str = dex_theme
|
|
46
|
+
self._on_dex_ready = on_dex_ready
|
|
47
|
+
|
|
48
|
+
def did_mount(self) -> None:
|
|
49
|
+
"""Chamado pelo Flet quando o controle é inserido na árvore."""
|
|
50
|
+
super().did_mount()
|
|
51
|
+
if self._on_dex_ready:
|
|
52
|
+
self._on_dex_ready(self)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DEx_PopupMenuButton — DEx-Framework v3.0.0
|
|
3
|
+
Encapsula flet.PopupMenuButton com padrões DEx.
|
|
4
|
+
|
|
5
|
+
Uso básico:
|
|
6
|
+
from dex_framework.buttons import DEx_PopupMenuButton
|
|
7
|
+
componente = DEx_PopupMenuButton(...)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
import flet as ft
|
|
12
|
+
from typing import Any, Callable, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DEx_PopupMenuButton(ft.PopupMenuButton):
|
|
16
|
+
"""
|
|
17
|
+
Encapsulamento DEx do controle flet.PopupMenuButton.
|
|
18
|
+
|
|
19
|
+
Mantém 100% da API original do Flet e adiciona:
|
|
20
|
+
- Valores padrão opinados (brand defaults)
|
|
21
|
+
- Parâmetro `dex_id` para rastreamento
|
|
22
|
+
- Hook `on_dex_ready` disparado após montagem
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
dex_id: Identificador único do componente na aplicação.
|
|
26
|
+
on_dex_ready: Callback chamado quando o componente é montado.
|
|
27
|
+
**kwargs: Todos os parâmetros nativos de flet.PopupMenuButton.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
>>> btn = DEx_PopupMenuButton(
|
|
31
|
+
... dex_id="exemplo",
|
|
32
|
+
... )
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
*args: Any,
|
|
38
|
+
dex_id: str = "",
|
|
39
|
+
dex_theme: str = "dell",
|
|
40
|
+
on_dex_ready: Optional[Callable[["DEx_PopupMenuButton"], None]] = None,
|
|
41
|
+
**kwargs: Any,
|
|
42
|
+
) -> None:
|
|
43
|
+
super().__init__(*args, **kwargs)
|
|
44
|
+
self.dex_id: str = dex_id
|
|
45
|
+
self.dex_theme: str = dex_theme
|
|
46
|
+
self._on_dex_ready = on_dex_ready
|
|
47
|
+
|
|
48
|
+
def did_mount(self) -> None:
|
|
49
|
+
"""Chamado pelo Flet quando o controle é inserido na árvore."""
|
|
50
|
+
super().did_mount()
|
|
51
|
+
if self._on_dex_ready:
|
|
52
|
+
self._on_dex_ready(self)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DEx_SubmenuButton — DEx-Framework v3.0.0
|
|
3
|
+
Encapsula flet.SubmenuButton com padrões DEx.
|
|
4
|
+
|
|
5
|
+
Uso básico:
|
|
6
|
+
from dex_framework.buttons import DEx_SubmenuButton
|
|
7
|
+
componente = DEx_SubmenuButton(...)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
import flet as ft
|
|
12
|
+
from typing import Any, Callable, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DEx_SubmenuButton(ft.SubmenuButton):
|
|
16
|
+
"""
|
|
17
|
+
Encapsulamento DEx do controle flet.SubmenuButton.
|
|
18
|
+
|
|
19
|
+
Mantém 100% da API original do Flet e adiciona:
|
|
20
|
+
- Valores padrão opinados (brand defaults)
|
|
21
|
+
- Parâmetro `dex_id` para rastreamento
|
|
22
|
+
- Hook `on_dex_ready` disparado após montagem
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
dex_id: Identificador único do componente na aplicação.
|
|
26
|
+
on_dex_ready: Callback chamado quando o componente é montado.
|
|
27
|
+
**kwargs: Todos os parâmetros nativos de flet.SubmenuButton.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
>>> btn = DEx_SubmenuButton(
|
|
31
|
+
... dex_id="exemplo",
|
|
32
|
+
... )
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
*args: Any,
|
|
38
|
+
dex_id: str = "",
|
|
39
|
+
dex_theme: str = "dell",
|
|
40
|
+
on_dex_ready: Optional[Callable[["DEx_SubmenuButton"], None]] = None,
|
|
41
|
+
**kwargs: Any,
|
|
42
|
+
) -> None:
|
|
43
|
+
super().__init__(*args, **kwargs)
|
|
44
|
+
self.dex_id: str = dex_id
|
|
45
|
+
self.dex_theme: str = dex_theme
|
|
46
|
+
self._on_dex_ready = on_dex_ready
|
|
47
|
+
|
|
48
|
+
def did_mount(self) -> None:
|
|
49
|
+
"""Chamado pelo Flet quando o controle é inserido na árvore."""
|
|
50
|
+
super().did_mount()
|
|
51
|
+
if self._on_dex_ready:
|
|
52
|
+
self._on_dex_ready(self)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DEx_TextButton — DEx-Framework v3.0.0
|
|
3
|
+
Encapsula flet.TextButton com padrões DEx.
|
|
4
|
+
|
|
5
|
+
Uso básico:
|
|
6
|
+
from dex_framework.buttons import DEx_TextButton
|
|
7
|
+
componente = DEx_TextButton(...)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
import flet as ft
|
|
12
|
+
from typing import Any, Callable, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DEx_TextButton(ft.TextButton):
|
|
16
|
+
"""
|
|
17
|
+
Encapsulamento DEx do controle flet.TextButton.
|
|
18
|
+
|
|
19
|
+
Mantém 100% da API original do Flet e adiciona:
|
|
20
|
+
- Valores padrão opinados (brand defaults)
|
|
21
|
+
- Parâmetro `dex_id` para rastreamento
|
|
22
|
+
- Hook `on_dex_ready` disparado após montagem
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
dex_id: Identificador único do componente na aplicação.
|
|
26
|
+
on_dex_ready: Callback chamado quando o componente é montado.
|
|
27
|
+
**kwargs: Todos os parâmetros nativos de flet.TextButton.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
>>> btn = DEx_TextButton(
|
|
31
|
+
... dex_id="exemplo",
|
|
32
|
+
... )
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
*args: Any,
|
|
38
|
+
dex_id: str = "",
|
|
39
|
+
dex_theme: str = "dell",
|
|
40
|
+
on_dex_ready: Optional[Callable[["DEx_TextButton"], None]] = None,
|
|
41
|
+
**kwargs: Any,
|
|
42
|
+
) -> None:
|
|
43
|
+
super().__init__(*args, **kwargs)
|
|
44
|
+
self.dex_id: str = dex_id
|
|
45
|
+
self.dex_theme: str = dex_theme
|
|
46
|
+
self._on_dex_ready = on_dex_ready
|
|
47
|
+
|
|
48
|
+
def did_mount(self) -> None:
|
|
49
|
+
"""Chamado pelo Flet quando o controle é inserido na árvore."""
|
|
50
|
+
super().did_mount()
|
|
51
|
+
if self._on_dex_ready:
|
|
52
|
+
self._on_dex_ready(self)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from .DEx_ElevatedButton import DEx_ElevatedButton
|
|
2
|
+
from .DEx_FilledButton import DEx_FilledButton
|
|
3
|
+
from .DEx_FilledTonalButton import DEx_FilledTonalButton
|
|
4
|
+
from .DEx_OutlinedButton import DEx_OutlinedButton
|
|
5
|
+
from .DEx_TextButton import DEx_TextButton
|
|
6
|
+
from .DEx_IconButton import DEx_IconButton
|
|
7
|
+
from .DEx_FloatingActionButton import DEx_FloatingActionButton
|
|
8
|
+
from .DEx_PopupMenuButton import DEx_PopupMenuButton
|
|
9
|
+
from .DEx_MenuItemButton import DEx_MenuItemButton
|
|
10
|
+
from .DEx_SubmenuButton import DEx_SubmenuButton
|
|
11
|
+
from .DEx_CupertinoButton import DEx_CupertinoButton
|
|
12
|
+
from .DEx_CupertinoFilledButton import DEx_CupertinoFilledButton
|
|
13
|
+
from .DEx_ActionButtons import DEx_ActionButton, DEx_ActionButtons
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"DEx_ElevatedButton",
|
|
17
|
+
"DEx_FilledButton",
|
|
18
|
+
"DEx_FilledTonalButton",
|
|
19
|
+
"DEx_OutlinedButton",
|
|
20
|
+
"DEx_TextButton",
|
|
21
|
+
"DEx_IconButton",
|
|
22
|
+
"DEx_FloatingActionButton",
|
|
23
|
+
"DEx_PopupMenuButton",
|
|
24
|
+
"DEx_MenuItemButton",
|
|
25
|
+
"DEx_SubmenuButton",
|
|
26
|
+
"DEx_CupertinoButton",
|
|
27
|
+
"DEx_CupertinoFilledButton",
|
|
28
|
+
"DEx_ActionButton",
|
|
29
|
+
"DEx_ActionButtons",
|
|
30
|
+
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DEx_Canvas — DEx-Framework v3.0.0
|
|
3
|
+
Encapsula flet.canvas.Canvas com padrões DEx.
|
|
4
|
+
|
|
5
|
+
Uso básico:
|
|
6
|
+
from dex_framework.canvas import DEx_Canvas
|
|
7
|
+
componente = DEx_Canvas(...)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
import flet as ft
|
|
12
|
+
import flet.canvas as cv
|
|
13
|
+
from typing import Any, Callable, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DEx_Canvas(cv.Canvas):
|
|
17
|
+
"""
|
|
18
|
+
Encapsulamento DEx do controle flet.canvas.Canvas.
|
|
19
|
+
|
|
20
|
+
Mantém 100% da API original do Flet e adiciona:
|
|
21
|
+
- Parâmetro `dex_id` para rastreamento
|
|
22
|
+
- Hook `on_dex_ready` disparado após montagem
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
dex_id: Identificador único do componente na aplicação.
|
|
26
|
+
on_dex_ready: Callback chamado quando o componente é montado.
|
|
27
|
+
**kwargs: Todos os parâmetros nativos de flet.canvas.Canvas.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
>>> canvas = DEx_Canvas(dex_id="meu_canvas")
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
*args: Any,
|
|
36
|
+
dex_id: str = "",
|
|
37
|
+
dex_theme: str = "dell",
|
|
38
|
+
on_dex_ready: Optional[Callable[["DEx_Canvas"], None]] = None,
|
|
39
|
+
**kwargs: Any,
|
|
40
|
+
) -> None:
|
|
41
|
+
super().__init__(*args, **kwargs)
|
|
42
|
+
self.dex_id: str = dex_id
|
|
43
|
+
self.dex_theme: str = dex_theme
|
|
44
|
+
self._on_dex_ready = on_dex_ready
|
|
45
|
+
|
|
46
|
+
def did_mount(self) -> None:
|
|
47
|
+
"""Chamado pelo Flet quando o controle é inserido na árvore."""
|
|
48
|
+
super().did_mount()
|
|
49
|
+
if self._on_dex_ready:
|
|
50
|
+
self._on_dex_ready(self)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DEx_BarChart — DEx-Framework v3.0.0
|
|
3
|
+
Stub: flet.BarChart não está disponível no flet 0.84.0 base.
|
|
4
|
+
Requer pacote adicional (flet-charts).
|
|
5
|
+
|
|
6
|
+
Uso básico:
|
|
7
|
+
from dex_framework.charts import DEx_BarChart
|
|
8
|
+
componente = DEx_BarChart(bar_groups=[...], dex_id="chart")
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
import flet as ft
|
|
13
|
+
from typing import Any, Callable, List, Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DEx_BarChart(ft.Container):
|
|
17
|
+
"""
|
|
18
|
+
Stub DEx para BarChart.
|
|
19
|
+
|
|
20
|
+
flet.BarChart não está disponível no flet 0.84.0 padrão.
|
|
21
|
+
Requer instalação do pacote flet-charts.
|
|
22
|
+
Este stub preserva a interface sem quebrar imports.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
bar_groups: Lista de BarChartGroup com dados.
|
|
26
|
+
max_y: Valor máximo do eixo Y.
|
|
27
|
+
left_axis: Configuração do eixo esquerdo.
|
|
28
|
+
bottom_axis: Configuração do eixo inferior.
|
|
29
|
+
dex_id: Identificador único do componente na aplicação.
|
|
30
|
+
on_dex_ready: Callback chamado quando o componente é montado.
|
|
31
|
+
**kwargs: Parâmetros adicionais.
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
>>> chart = DEx_BarChart(bar_groups=[...], dex_id="vendas")
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
*args: Any,
|
|
40
|
+
bar_groups: Optional[List[Any]] = None,
|
|
41
|
+
max_y: Optional[float] = None,
|
|
42
|
+
left_axis: Any = None,
|
|
43
|
+
bottom_axis: Any = None,
|
|
44
|
+
dex_id: str = "",
|
|
45
|
+
dex_theme: str = "dell",
|
|
46
|
+
on_dex_ready: Optional[Callable[["DEx_BarChart"], None]] = None,
|
|
47
|
+
**kwargs: Any,
|
|
48
|
+
) -> None:
|
|
49
|
+
self.dex_id: str = dex_id
|
|
50
|
+
self.dex_theme: str = dex_theme
|
|
51
|
+
self._on_dex_ready = on_dex_ready
|
|
52
|
+
self.bar_groups = bar_groups or []
|
|
53
|
+
self.max_y = max_y
|
|
54
|
+
self.left_axis = left_axis
|
|
55
|
+
self.bottom_axis = bottom_axis
|
|
56
|
+
kwargs.pop("content", None)
|
|
57
|
+
kwargs.pop("bgcolor", None)
|
|
58
|
+
kwargs.pop("alignment", None)
|
|
59
|
+
kwargs.pop("border", None)
|
|
60
|
+
super().__init__(
|
|
61
|
+
content=ft.Column(
|
|
62
|
+
controls=[
|
|
63
|
+
ft.Icon(ft.Icons.BAR_CHART, size=48, color=ft.Colors.GREY_400),
|
|
64
|
+
ft.Text(
|
|
65
|
+
"[BarChart stub — instale flet-charts]",
|
|
66
|
+
color=ft.Colors.GREY,
|
|
67
|
+
italic=True,
|
|
68
|
+
),
|
|
69
|
+
],
|
|
70
|
+
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
|
|
71
|
+
),
|
|
72
|
+
bgcolor=ft.Colors.GREY_50,
|
|
73
|
+
alignment=ft.Alignment(0, 0),
|
|
74
|
+
border=ft.Border.all(1, ft.Colors.GREY_300),
|
|
75
|
+
**kwargs,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def did_mount(self) -> None:
|
|
79
|
+
"""Chamado pelo Flet quando o controle é inserido na árvore."""
|
|
80
|
+
super().did_mount()
|
|
81
|
+
if self._on_dex_ready:
|
|
82
|
+
self._on_dex_ready(self)
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DEx_CandlestickChart — DEx-Framework v3.0.0
|
|
3
|
+
Gráfico de candlestick (OHLC) desenhado nativamente via ft.canvas.
|
|
4
|
+
|
|
5
|
+
Não requer dependências externas — usa apenas flet.canvas disponível no
|
|
6
|
+
flet 0.84.0 padrão.
|
|
7
|
+
|
|
8
|
+
Uso básico:
|
|
9
|
+
from dex_framework.charts import DEx_CandlestickChart, DEx_Candle
|
|
10
|
+
|
|
11
|
+
candles = [
|
|
12
|
+
DEx_Candle("Jan", open=100, high=120, low=90, close=115),
|
|
13
|
+
DEx_Candle("Fev", open=115, high=130, low=110, close=108),
|
|
14
|
+
]
|
|
15
|
+
chart = DEx_CandlestickChart(candles=candles, dex_id="chart_ohlc")
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import flet as ft
|
|
21
|
+
import flet.canvas as cv
|
|
22
|
+
from dataclasses import dataclass
|
|
23
|
+
from typing import Any, Callable, List, Optional
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ── Modelo de dado ────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class DEx_Candle:
|
|
30
|
+
"""
|
|
31
|
+
Representa uma vela (candle) OHLC.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
label: Rótulo exibido no eixo X (ex: "Jan", "2024").
|
|
35
|
+
open: Preço / valor de abertura.
|
|
36
|
+
high: Máxima do período.
|
|
37
|
+
low: Mínima do período.
|
|
38
|
+
close: Preço / valor de fechamento.
|
|
39
|
+
"""
|
|
40
|
+
label: str
|
|
41
|
+
open: float
|
|
42
|
+
high: float
|
|
43
|
+
low: float
|
|
44
|
+
close: float
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ── Componente ────────────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
class DEx_CandlestickChart(ft.Container):
|
|
50
|
+
"""
|
|
51
|
+
Gráfico de candlestick desenhado nativamente via ft.canvas.
|
|
52
|
+
|
|
53
|
+
Cada vela exibe wick (pavio) e corpo colorido:
|
|
54
|
+
- Verde → fechamento acima da abertura (bullish)
|
|
55
|
+
- Vermelho → fechamento abaixo da abertura (bearish)
|
|
56
|
+
- Cinza → fechamento igual à abertura (neutral)
|
|
57
|
+
|
|
58
|
+
Recursos:
|
|
59
|
+
- Escala Y automática com padding
|
|
60
|
+
- Grade horizontal configurável
|
|
61
|
+
- Rótulos nos eixos X e Y
|
|
62
|
+
- Título opcional
|
|
63
|
+
- Largura das velas proporcional ao slot disponível
|
|
64
|
+
- Sem dependências externas
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
candles: Lista de :class:`DEx_Candle` com os dados OHLC.
|
|
68
|
+
title: Título exibido no topo do gráfico.
|
|
69
|
+
width: Largura total do gráfico em pixels.
|
|
70
|
+
height: Altura total do gráfico em pixels.
|
|
71
|
+
candle_width_ratio: Fração do slot ocupada pelo corpo (0.0–1.0).
|
|
72
|
+
bullish_color: Cor da vela de alta.
|
|
73
|
+
bearish_color: Cor da vela de baixa.
|
|
74
|
+
neutral_color: Cor da vela neutra.
|
|
75
|
+
grid_color: Cor das linhas de grade.
|
|
76
|
+
show_grid: Exibe ou oculta a grade horizontal.
|
|
77
|
+
y_decimals: Casas decimais dos rótulos do eixo Y.
|
|
78
|
+
dex_id: Identificador único do componente.
|
|
79
|
+
dex_theme: Nome do tema de marca.
|
|
80
|
+
on_dex_ready: Callback chamado após montagem.
|
|
81
|
+
**kwargs: Parâmetros adicionais repassados a ``ft.Container``.
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
>>> chart = DEx_CandlestickChart(
|
|
85
|
+
... candles=[DEx_Candle("Jan", 100, 120, 90, 115)],
|
|
86
|
+
... title="OHLC Mensal",
|
|
87
|
+
... dex_id="chart_ohlc",
|
|
88
|
+
... )
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
_MARGIN_LEFT = 62
|
|
92
|
+
_MARGIN_RIGHT = 14
|
|
93
|
+
_MARGIN_TOP = 20
|
|
94
|
+
_MARGIN_BOTTOM = 30
|
|
95
|
+
_GRID_LINES = 5
|
|
96
|
+
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
candles: List[DEx_Candle],
|
|
100
|
+
*,
|
|
101
|
+
title: str = "",
|
|
102
|
+
width: float = 600,
|
|
103
|
+
height: float = 320,
|
|
104
|
+
candle_width_ratio: float = 0.55,
|
|
105
|
+
bullish_color: str = ft.Colors.GREEN_600,
|
|
106
|
+
bearish_color: str = ft.Colors.RED_500,
|
|
107
|
+
neutral_color: str = ft.Colors.BLUE_GREY_400,
|
|
108
|
+
grid_color: str = ft.Colors.OUTLINE_VARIANT,
|
|
109
|
+
show_grid: bool = True,
|
|
110
|
+
y_decimals: int = 0,
|
|
111
|
+
# DEx
|
|
112
|
+
dex_id: str = "",
|
|
113
|
+
dex_theme: str = "dell",
|
|
114
|
+
on_dex_ready: Optional[Callable[["DEx_CandlestickChart"], None]] = None,
|
|
115
|
+
**kwargs: Any,
|
|
116
|
+
) -> None:
|
|
117
|
+
self._candles = candles
|
|
118
|
+
self._title = title
|
|
119
|
+
self._w = width
|
|
120
|
+
self._h = height
|
|
121
|
+
self._candle_ratio = max(0.1, min(candle_width_ratio, 0.95))
|
|
122
|
+
self._bullish = bullish_color
|
|
123
|
+
self._bearish = bearish_color
|
|
124
|
+
self._neutral = neutral_color
|
|
125
|
+
self._grid_color = grid_color
|
|
126
|
+
self._show_grid = show_grid
|
|
127
|
+
self._y_dec = y_decimals
|
|
128
|
+
|
|
129
|
+
self.dex_id = dex_id
|
|
130
|
+
self.dex_theme = dex_theme
|
|
131
|
+
self._on_dex_ready = on_dex_ready
|
|
132
|
+
|
|
133
|
+
kwargs.pop("content", None)
|
|
134
|
+
|
|
135
|
+
super().__init__(
|
|
136
|
+
width=width,
|
|
137
|
+
height=height,
|
|
138
|
+
content=self._build_canvas(),
|
|
139
|
+
**kwargs,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# ── Helpers de coordenadas ────────────────────────────────────────────────
|
|
143
|
+
|
|
144
|
+
def _y_range(self) -> tuple[float, float]:
|
|
145
|
+
"""Calcula min/max com padding de 8%."""
|
|
146
|
+
lows = [c.low for c in self._candles]
|
|
147
|
+
highs = [c.high for c in self._candles]
|
|
148
|
+
lo, hi = min(lows), max(highs)
|
|
149
|
+
pad = (hi - lo) * 0.08 or abs(hi) * 0.05 or 1.0
|
|
150
|
+
return lo - pad, hi + pad
|
|
151
|
+
|
|
152
|
+
def _to_y(self, value: float, lo: float, hi: float) -> float:
|
|
153
|
+
chart_h = self._h - self._MARGIN_TOP - self._MARGIN_BOTTOM
|
|
154
|
+
ratio = (value - lo) / (hi - lo) if hi != lo else 0.5
|
|
155
|
+
return self._MARGIN_TOP + chart_h * (1.0 - ratio)
|
|
156
|
+
|
|
157
|
+
def _slot(self, i: int) -> tuple[float, float]:
|
|
158
|
+
"""Retorna (centro_x, largura_slot) para o índice i."""
|
|
159
|
+
n = len(self._candles)
|
|
160
|
+
chart_w = self._w - self._MARGIN_LEFT - self._MARGIN_RIGHT
|
|
161
|
+
sw = chart_w / n
|
|
162
|
+
cx = self._MARGIN_LEFT + sw * i + sw / 2.0
|
|
163
|
+
return cx, sw
|
|
164
|
+
|
|
165
|
+
# ── Construção do canvas ──────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
def _build_canvas(self) -> cv.Canvas:
|
|
168
|
+
shapes: list = []
|
|
169
|
+
|
|
170
|
+
lbl_style = ft.TextStyle(size=9, color=ft.Colors.ON_SURFACE_VARIANT)
|
|
171
|
+
title_style = ft.TextStyle(size=11, weight=ft.FontWeight.W_600,
|
|
172
|
+
color=ft.Colors.ON_SURFACE)
|
|
173
|
+
|
|
174
|
+
if not self._candles:
|
|
175
|
+
shapes.append(cv.Text(
|
|
176
|
+
x=self._w / 2, y=self._h / 2,
|
|
177
|
+
value="Sem dados",
|
|
178
|
+
style=ft.TextStyle(size=13, color=ft.Colors.ON_SURFACE_VARIANT),
|
|
179
|
+
alignment=ft.Alignment(0, 0),
|
|
180
|
+
))
|
|
181
|
+
return cv.Canvas(shapes=shapes, width=self._w, height=self._h)
|
|
182
|
+
|
|
183
|
+
lo, hi = self._y_range()
|
|
184
|
+
chart_h = self._h - self._MARGIN_TOP - self._MARGIN_BOTTOM
|
|
185
|
+
chart_w = self._w - self._MARGIN_LEFT - self._MARGIN_RIGHT
|
|
186
|
+
|
|
187
|
+
# ── Título ────────────────────────────────────────────────────────
|
|
188
|
+
if self._title:
|
|
189
|
+
shapes.append(cv.Text(
|
|
190
|
+
x=self._MARGIN_LEFT + chart_w / 2,
|
|
191
|
+
y=4,
|
|
192
|
+
value=self._title,
|
|
193
|
+
style=title_style,
|
|
194
|
+
alignment=ft.Alignment(0, -1),
|
|
195
|
+
))
|
|
196
|
+
|
|
197
|
+
# ── Grade + rótulos Y ─────────────────────────────────────────────
|
|
198
|
+
for i in range(self._GRID_LINES + 1):
|
|
199
|
+
ratio = i / self._GRID_LINES
|
|
200
|
+
gy = self._MARGIN_TOP + chart_h * (1.0 - ratio)
|
|
201
|
+
val = lo + (hi - lo) * ratio
|
|
202
|
+
|
|
203
|
+
if self._show_grid:
|
|
204
|
+
shapes.append(cv.Line(
|
|
205
|
+
x1=self._MARGIN_LEFT, y1=gy,
|
|
206
|
+
x2=self._MARGIN_LEFT + chart_w, y2=gy,
|
|
207
|
+
paint=ft.Paint(
|
|
208
|
+
color=self._grid_color,
|
|
209
|
+
stroke_width=1.0 if i == 0 else 0.5,
|
|
210
|
+
),
|
|
211
|
+
))
|
|
212
|
+
|
|
213
|
+
fmt = f"{val:,.{self._y_dec}f}"
|
|
214
|
+
shapes.append(cv.Text(
|
|
215
|
+
x=self._MARGIN_LEFT - 5, y=gy,
|
|
216
|
+
value=fmt,
|
|
217
|
+
style=lbl_style,
|
|
218
|
+
alignment=ft.Alignment(1, 0),
|
|
219
|
+
))
|
|
220
|
+
|
|
221
|
+
# ── Eixo esquerdo (borda) ─────────────────────────────────────────
|
|
222
|
+
shapes.append(cv.Line(
|
|
223
|
+
x1=self._MARGIN_LEFT, y1=self._MARGIN_TOP,
|
|
224
|
+
x2=self._MARGIN_LEFT, y2=self._MARGIN_TOP + chart_h,
|
|
225
|
+
paint=ft.Paint(color=ft.Colors.OUTLINE_VARIANT, stroke_width=1),
|
|
226
|
+
))
|
|
227
|
+
|
|
228
|
+
# ── Velas ─────────────────────────────────────────────────────────
|
|
229
|
+
for i, c in enumerate(self._candles):
|
|
230
|
+
cx, sw = self._slot(i)
|
|
231
|
+
cw = max(sw * self._candle_ratio, 2.0)
|
|
232
|
+
|
|
233
|
+
oy = self._to_y(c.open, lo, hi)
|
|
234
|
+
cly = self._to_y(c.close, lo, hi)
|
|
235
|
+
hy = self._to_y(c.high, lo, hi)
|
|
236
|
+
ly = self._to_y(c.low, lo, hi)
|
|
237
|
+
|
|
238
|
+
# Cor da vela
|
|
239
|
+
if c.close > c.open:
|
|
240
|
+
color = self._bullish
|
|
241
|
+
elif c.close < c.open:
|
|
242
|
+
color = self._bearish
|
|
243
|
+
else:
|
|
244
|
+
color = self._neutral
|
|
245
|
+
|
|
246
|
+
# Pavio (wick)
|
|
247
|
+
shapes.append(cv.Line(
|
|
248
|
+
x1=cx, y1=hy, x2=cx, y2=ly,
|
|
249
|
+
paint=ft.Paint(color=color, stroke_width=1.5),
|
|
250
|
+
))
|
|
251
|
+
|
|
252
|
+
# Corpo (body)
|
|
253
|
+
body_top = min(oy, cly)
|
|
254
|
+
body_h = max(abs(cly - oy), 2.0)
|
|
255
|
+
|
|
256
|
+
shapes.append(cv.Rect(
|
|
257
|
+
x=cx - cw / 2, y=body_top,
|
|
258
|
+
width=cw, height=body_h,
|
|
259
|
+
paint=ft.Paint(color=color, style=ft.PaintingStyle.FILL),
|
|
260
|
+
))
|
|
261
|
+
shapes.append(cv.Rect(
|
|
262
|
+
x=cx - cw / 2, y=body_top,
|
|
263
|
+
width=cw, height=body_h,
|
|
264
|
+
paint=ft.Paint(
|
|
265
|
+
color=ft.Colors.with_opacity(0.25, ft.Colors.ON_SURFACE),
|
|
266
|
+
stroke_width=0.5,
|
|
267
|
+
style=ft.PaintingStyle.STROKE,
|
|
268
|
+
),
|
|
269
|
+
))
|
|
270
|
+
|
|
271
|
+
# Rótulo X
|
|
272
|
+
shapes.append(cv.Text(
|
|
273
|
+
x=cx,
|
|
274
|
+
y=self._MARGIN_TOP + chart_h + 6,
|
|
275
|
+
value=c.label,
|
|
276
|
+
style=lbl_style,
|
|
277
|
+
alignment=ft.Alignment(0, -1),
|
|
278
|
+
))
|
|
279
|
+
|
|
280
|
+
return cv.Canvas(shapes=shapes, width=self._w, height=self._h)
|
|
281
|
+
|
|
282
|
+
# ── Ciclo de vida DEx ─────────────────────────────────────────────────────
|
|
283
|
+
|
|
284
|
+
def did_mount(self) -> None:
|
|
285
|
+
"""Chamado pelo Flet quando o controle é inserido na árvore."""
|
|
286
|
+
super().did_mount()
|
|
287
|
+
if self._on_dex_ready:
|
|
288
|
+
self._on_dex_ready(self)
|