Metadata-Version: 2.5
Name: flexgui
Version: 1.0.2
Summary: Thư viện GUI Python kéo-thả-thiết-kế trên tkinter — FlexGUI Studio tích hợp (design mode + mini VS Code cho trigger)
Keywords: gui,tkinter,designer,drag-and-drop,visual-designer,no-code,vietnamese,flexgui
Author: FlexGUI Team
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Natural Language :: Vietnamese
License-File: LICENSE
Requires-Dist: pyinstaller>=6.0 ; extra == "build"
Project-URL: Documentation, https://github.com/your-name/flexgui#readme
Project-URL: Homepage, https://github.com/your-name/flexgui
Provides-Extra: build
Import-Name: flexgui

# FlexGUI

**Thư viện GUI Python kéo-thả-thiết-kế trên tkinter** — viết code siêu gọn,
thiết kế giao diện bằng chuột trong **FlexGUI Studio** (nền tối hiện đại),
code trigger sửa được **ngay trong Studio hoặc VS Code**, đóng gói `.exe`
một cú click.

```bash
pip install flexgui
```

---

## 1. Viết code thuần (60 giây)

```python
import flexgui
from flexgui import App, Label, Button, Input, Checkbox, Text

app = App("Ứng dụng của tôi", 860, 560)

Label("Xin chào!", 40, 30)            # label[1]
Button("Bấm tôi", 40, 80)             # button[2]
Input(40, 130, width=26)              # input[3]
Checkbox("Đồng ý", 40, 180)           # checkbox[4]
Text(40, 230, width=42, height=7)     # text[5]

app.run()
```

Mọi widget định vị **tuyệt đối bằng `place(x, y)`** — đặt đâu nằm đó,
chồng lớp tự do.

## 2. Chế độ thiết kế — FlexGUI Studio

Thêm **một dòng** vào file là mở được trình thiết kế:

```python
import flexgui

flexgui.setup()      # hoặc:  from flexgui import design; design.mode = True
```

Chạy `python myapp.py` → **Studio tự mở giao diện trống** (hoặc nạp
thiết kế đã lưu). Tính năng:

- Kéo thả mượt (canvas item — không tàn ảnh), **snap lưới 10px** (bật/tắt)
- **Resize 8 núm** quanh thành phần đang chọn
- **Multi-select**: Ctrl/Shift + click, quét vùng chuột, kéo cả cụm
- Đổi z-order (menu chuột phải), nhân bản `Ctrl+D`, undo/redo `Ctrl+Z/Y`
- Bảng thuộc tính bên phải: chữ, tọa độ, kích thước **pixel WYSIWYG**,
  màu chữ/nền, cỡ chữ, **độ trong suốt 0–100%**, ẩn khi chạy, khoá...
- **Xem trước F5** — chạy thử app thật + trigger thật ngay tại chỗ
- **Build .exe** bằng PyInstaller (nút ❖ — tự cài nếu thiếu)
- **Xuất .py** — 1 file tự chạy nhúng toàn bộ thiết kế + trigger

`Ctrl+S` lưu 2 file cạnh `myapp.py`:

| File | Nội dung |
|---|---|
| `myapp.flexgui.json` | bố cục + thuộc tính mọi thành phần |
| `myapp.triggers.py` | **code trigger — file dùng chung** |

## 3. Trigger — sửa ở Studio HOẶC VS Code đều được

`myapp.triggers.py` là file Python thật: mở bằng **mini VS Code** trong
Studio (nút `</> Triggers`) **hoặc** VS Code ngoài — cả hai sửa cùng một file.

```python
# myapp.triggers.py — label/button/... đã có sẵn, không cần import

def on_start():                       # chạy 1 lần khi app mở
    label[1].set_text("Xin chào!")

def on_button_2_click():              # bấm button[2]
    import random                     # Python thật — import gì cũng được
    label[1].set_text(f"Số: {random.randint(1, 99)}")

def on_checkbox_4_toggle():           # tick/bỏ tick checkbox[4]
    text[5].visible = checkbox[4].checked

def on_input_3_enter():               # Enter trong input[3]
    alert("Bạn vừa gõ: " + input[3].text)

def on_text_5_change():               # gõ chữ trong text[5]
    pass
```

Quy ước tên hàm: `on_<loại>_<id>_<sự kiện>`
(`click` / `toggle` / `enter` / `change`). Studio tự sinh sườn hàm khi lưu.

Kiểu **decorator** mạnh hơn (cũng viết trong file trigger):

```python
@on_click(button[2])
def xu_ly(): ...

@on_change(input[3])                  # gõ bất kỳ chữ nào
def khi_go(): ...

@when(lambda: checkbox[4].checked and input[3].text == "admin")
def khi_du(): ...                     # điều kiện SAI → ĐÚNG mới chạy

@every(1000)                          # lặp mỗi giây
def dong_ho(): ...

@on_init                              # = on_start
def khoi_dong(): ...
```

## 4. Chạy thật

Đổi 1 dòng trong `myapp.py`:

```python
import flexgui

flexgui.run(__file__)    # nạp myapp.flexgui.json + myapp.triggers.py
```

Hoặc dùng cờ dòng lệnh quen thuộc: `python myapp.py --design`.

## 5. Thuộc tính & lệnh điều khiển widget

```python
from flexgui import label, button, input, checkbox, text

label[1].text = "Số đếm: 5"       # đọc/ghi trực tiếp
label[1].set_text("...")          # tương đương
label[1].get_text()
label[1].x = 200                  # tọa độ pixel (đọc/ghi)
label[1].color = "red"            # màu chữ
label[1].bg = "#FFF3B0"           # màu nền GỐC
label[1].font_size = 14
label[1].transparency = 70         # ĐỘ TRONG SUỐT nền 0–100%
label[1].visible = False          # tàng hình / hiện lại
label[1].enabled = False          # khoá / mở
label[1].place(120, 80)           # đặt lại vị trí tuyệt đối
label[1].move(10, 0)              # dịch tương đối
label[1].resize(220, 30)          # cỡ pixel WYSIWYG
label[1].refresh()                # vẽ lại mọi thuộc tính đã lưu
label[1].show() / .hide() / .focus()

checkbox[4].checked = True        # (chỉ Checkbox)
checkbox[4].toggle()
button[2].command = ham_xu_ly     # gán lệnh bằng code

# Lệnh app — gọi thẳng trong trigger
refresh() · set_title("...") · set_size(1024, 640) · set_bg("black")
alert("...") · confirm("...?") → True/False · prompt("Tên?") → str/None
close_app()
```

### Độ trong suốt (transparent background)

`transparency` chạy từ `0` (nền đậm nguyên gốc) đến `100` (hòa hoàn toàn
vào màu nền cửa sổ — trông như không có nền). tkinter không có alpha thật
cho từng widget nên FlexGUI **pha màu nền widget về đúng màu nền cửa sổ**:

```python
label[1].bg = "#0078d4"            # nền xanh đậm
label[1].transparency = 50         # → xanh nhạt ngang nền cửa sổ
label[1].transparency = 100         # → nhìn như label không có nền
set_bg("#fff8e1")                  # đổi nền cửa sổ — mọi widget
                                   #   trong suốt tự PHA LẠI theo nền mới
```

Trong **Studio**: chọn thành phần → bảng phải → hàng **“Trong suốt”** có
thanh trượt 0–100% (bước 5). Canvas hiển thị đúng hiệu ứng + huy hiệu `%`
góc trên để nhận biết, lưu vào `myapp.flexgui.json` và cả file xuất `.py`.

Widget bị xóa thì `input[3]` trả **widget rỗng an toàn** — code cũ không
bao giờ văng lỗi. ID **tái sử dụng**: xóa `input[3]` rồi thêm widget mới
thì widget mới nhận lại đúng ID `[3]`.

---

## Đóng gói & chia sẻ

- **Build .exe** (nút ❖ trong Studio): PyInstaller tự động — file nằm
  trong `flexgui_build/dist/`.
- **Xuất .py** (nút ▲): 1 file duy nhất nhúng thiết kế + trigger — chạy
  bằng `python ten_file.py` (cần `pip install flexgui`).

## Cấu trúc package

```
flexgui/
├── __init__.py    # API công khai: App, 5 widget, run/setup/design...
├── mode.py        # design.mode = True
├── registry.py    # label[1] / button[2] ... + widget rỗng an toàn
├── widgets.py     # Label/Button/Input/Checkbox/Text (pixel WYSIWYG)
├── triggers.py    # engine trigger + decorator + lệnh app
├── app.py         # cửa sổ App + ID tái sử dụng
├── runtime.py     # run() / setup() / run_embedded()
├── editor.py      # mini VS Code (tô màu Python, IME tiếng Việt an toàn)
├── designer.py    # FlexGUI Studio (canvas Figma-style)
└── builder.py     # xuất file đơn + PyInstaller
```

## Yêu cầu

- Python 3.8+ (chỉ dùng thư viện chuẩn — **không cần cài thêm gì**)
- Build `.exe` cần `pip install pyinstaller` (Studio tự cài nếu thiếu)

## Lịch sử phiên bản

- **1.0.2** — **Sửa lỗi "Xem trước" (F5) mở lại Studio**: khi file người
  dùng còn `flexgui.setup()` (hoặc `design.mode = True`, hoặc chạy với cờ
  `--design`), bấm "Xem trước" trước đây làm cửa sổ preview tự hủy rồi mở
  thêm một Studio mới. Giờ cửa sổ xem trước **luôn chạy app thật + trigger
  thật**, không cần sửa file trước khi xem trước.
- **1.0.1** — Sửa nút toolbar bị ẩn/ô trống (lỗi không truyền chữ vào nút;
  thay ký hiệu bằng bộ glyph an toàn đa nền tảng — không còn ô vuông
  trống trên Linux); **thêm độ trong suốt `transparency` 0–100%** cho cả
  5 widget (thanh trượt trong bảng thuộc tính + pha màu tự động khi đổi
  nền cửa sổ); tương thích Tk 8.6 & 9.x.
- **1.0.0** — Bản đầu: package PyPI, `flexgui.setup()` / `design.mode`,
  Studio canvas Figma-style, trigger sửa 2 đầu Studio + VS Code.

## Đăng package lên PyPI (cho người phát hành)

```bash
pip install --upgrade build twine

# 1. build sdist + wheel (ra thư mục dist/)
python -m build

# 2. đăng (cần tài khoản PyPI + API token tại pypi.org)
twine upload dist/*
```

Sau đó mọi người cài chỉ với `pip install flexgui`.
*Lưu ý: nếu tên `flexgui` đã bị ai chiếm trên PyPI, đổi `name` trong
`pyproject.toml` (ví dụ `flexgui-vn`) rồi build lại.*

## License

MIT

