# FJML
<img src="media/FJML_LOGO.png">
### FJML is a JSON based markup language which translates JSON files into Flet UI for web, mobile and desktop applications.
# Example:
```json title="ui.json"
{
"Header":{
"program_name":"Example",
"action_import":{
"import":"Actions",
"from":".path.to.func.file"
},
},
"Controls":[
{
"var_name":"msg",
"control_type":"Text",
"settings":{
"value":"Hello World",
"size":20,
"color":{"code_refs":"colors", "attr":"green"},
"weight":{
"control_type":"FontWeight",
"attr":"W_700"
}
}
},
{
"var_name":"msg_display",
"control_type":"Container",
"settings":{
"content":{"refs":"msg"},
"alignment":{"control_type":"alignment.center"},
"border_radius":10,
"padding":{
"control_type":"padding.symmetric",
"settings":{"horizontal":10, "vertical":8}
},
"width":200,
"ink":true,
"ink_color":{"code_refs":"colors", "attr":"grey"}
}
}
],
"UI":[
{
"route":"/",
"settings":{
"controls":[
{"refs":"msg_display"}
],
"horizontal_alignment":{"code_refs":"cross_align"},
"vertical_alignment":{"code_refs":"main_align"}
}
}
]
}
```
```python title="func.py"
from fjml import data_types as dt
import flet as ft
class Colors:
green: str = ft.colors.GREEN_600
grey: str = ft.colors.GREY_200
class Actions(dt.EventContainer):
def _page_setup(self):
...
def _imports(self):
self.colors: Colors = Colors()
self.cross_align: str = ft.CrossAxisAlignment.CENTER
self.main_align: str = ft.MainAxisAlignment.CENTER
```
```python title="main.py"
from fjml import load_program, Compiler, data_types as dt
from path.to.program import Actions
import flet as ft
class Paths:
PROGRAM: str = "path\\to\\program_folder"
COMPILED: str = "path\\to\\compiled_program\\compiled.fjml"
class App:
def __init__(self, compile_run: bool = False) -> None:
if compile_run:
compiler: Compiler = Compiler(Paths.PROGRAM, Paths.COMPILED)
compiler.compile()
async def run(self, page: ft.Page):
page = load_program(Paths.COMPILED, Actions)
page.go("/")
if __name__ == "__main__":
app: App = App(compile_run=True)
ft.app(target=app.run)
```
---
## CLI Tooling:
FJML comes with 2 CLI commands and each have specific parameters:
- `registry` :
The registry command is a categorical command which automatically modifies the registry file which contains of all Flet controls of your current Flet installation.
| Choice | Value Type | Action |
| ---------- | ---------- | --------------------- |
| **delete** | `str` | deletes registry file |
| **reset** | `str` | resets registry file |
Example:
- `fjml registry update`
The reset command should be used after installation to ensure proper functioning of fjml
- `make` :
The make command generates an FJML folder containing all the needed files for running your project.
make has one mandatory parameter, `--name`, and one optional parameter, `--path`.
`--name` generates the name of your project while `--path` directs where that project is generated. If path is not entered it will use the current directory.
Example:
- `fjml make --name Hello World`
---
## Python Integration
FJML allows the use of python code to perform actions such as API calls, function calls, etc. via the `EventContainer` Abstract Base Class.
- The main format of the Actions class which inherits from the `EventContainer` looks like this:
```python
from fjml.data_types import EventContainer
class Actions(EventContainer):
def _page_setup(self):
'''
a custom page setup function to initialize your page object with data
'''
def _imports(self):
'''
an import function used to run operations outside of the page before rendering the UI
'''
#you can then add custom functions to be used throughout the FJML code
```
`EventContainer` also includes multiple built-in helper classes and functions to help create programs
- ### `EventContainer` methods and classes
- ### **client_storage**:
#### See [Flet Page Docs](https://flet.dev/docs/cookbook/client-storage)
---
- ### **session**:
#### See [Flet Page Docs](https://flet.dev/docs/cookbook/session-storage)
---
- ### **update**:
#### equivalent to `ft.Page.update`
---
- ### **page**:
#### See [Flet Page Docs](https://flet.dev/docs/controls/page).
---
- ### **dict_to_control**:
| Name | Attributes | Return | Description |
| ------------------- | ------------------------- | ---------------- | --------------------------------------------------------------------- |
| **dict_to_control** | `control: dt.ControlDict` | `dt.ControlType` | Allows creating controls using FJML syntax inside the `EventContainer`. |
- #### Example Usage:
```python
class Actions(dt.EventContainer):
def make_control(self) -> ft.Control:
return self.dict_to_control({
"control_type":"Container",
"settings":{
"alignment":{"control_type":"alignment.center"},
"content":{
"control_type":"Text",
"settings":{
"value":"Hello World",
"size":18
}
}
}
})
```
---
- ### **group_assign**:
| Name | Attributes | Return | Description |
| ---------------- | ---------------------------------------------- | ------ | --------------------------------------------------------- |
| **group_assign** | `obj: Any', 'attribute_map: Mapping[str, Any]` | `None` | allows assigning multiple attributes to an object at once |
- #### Example Usage:
```python
class Data:
f_name: str
l_name: str
age: int
class Actions(dt.EventContainer):
def fill_data(self) -> Data:
data: Data = Data()
self.group_assign(
data,
{
"f_name":"John",
"l_name":"Doe",
"age":21
}
)
return data
```
---
- ### **eval_locals**:
#### This class's main use is to add or delete locals from the evil statement's locals parameter.
| Methods | Attributes | Return | Description |
| --------------- | ------------------------- | ------------------- | ----------------------------------------------------------------- |
| **add** | `name: str`, `obj: Any` | `None` | adds an object to the eval statement's locals |
| **delete** | `name: str` | `None` | deletes an object from the eval statement's locals |
| **mass_add** | `data: Mapping[str, Any]` | `None` | adds multiple objects to the eval statement's locals |
| **mass_delete** | `data: Sequence[str]` | `None` | deletes multiple objects from the eval statement's locals |
| **data** | `None` | `Mapping[str, Any]` | returns a copy of all preset locals in the eval statement's locals |
---
- ### **object_bucket**:
| Methods | Attributes | Return | Description |
| ----------------- | ------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------- |
| **set_object** | `name: str`, `obj: AnyCallable` | `None` | adds any callable object to the bucket, so it can be called inside the UI code |
| **call_object** | `name: str`, `kwargs: dict[str, Any]` | `Any` | calls the object with the necessary key word arguments. (used when object is called within the UI code) |
| **delete_object** | `name: str` | `None` | deletes the object from the bucket |
#### This class's main use is to register objects for use in FJML code via the "**call**" designator:
* ⠀
```json
{
"call":"get_text",
"settings":{
"index":1
}
}
```
#### If an object is not registered it can not be called but can only be referenced using a **code_refs** or the **func** designators.
---
- ### **property_bucket**:
| Methods | Attributes | Return | Description |
| ------------ | --------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **add** | `name: str`, `obj: Any` | `None` | adds a property to be used as a `code_refs` inside the UI code |
| **contains** | `name: str` | `bool` | used to check if a name is registered as property |
| **call** | `name: str`, `operation: str`, `set_val: Any` | `None` | Uses the property operations (set, get, del) to either set an object using the set_val parameter, get by just giving the name or deletion using the del operation. |
#### This class's main use is to register python functions as properties to be used as **code_refs**
---
- ### **setup_functions**:
#### This class's main use is to register functions to be called to set up what ever API, environment, etc. when the UI starts up.
| Methods | Attributes | Return | Description |
| ------------------ | ------------------------------------------------- | ------ | -------------------------------------- |
| **add_func** | `func: Callable`, `parameters: Sequence[Any]` | `None` | adds a function to the class |
| **mass_add_func** | `items: Sequence[tuple[Callable, Sequence[Any]]]` | `None` | adds multiple functions to the class |
| **call_functions** | `None` | `None` | calls all functions added to the class |
---
- ### **style_sheet**:
#### this class is used primarily for retrieving styles set inside the style sheet. This is mainly used in the "**_unpack**" designator via the `{"styling":"xyz"}` mapping value.
| Methods | Attributes | Return | Description |
| ------------- | ----------- | ------------- | ----------------------------------------- |
| **get_style** | `path: str` | `dt.JsonDict` | gets the style from a style sheet by name |
---
- ### **view_operations**:
#### This class is used to generate and register Flet views. Its main use is in the Flet's `Page.on_route_change` event.
| Methods | Attributes | Return | Description |
| ------------- | ------------------------------------------------------ | --------- | ----------------------------------------------------------- |
| **set_view** | `route_name: str`, `view_settings: dt.ControlSettings` | `None` | adds a `UIViews` to the compiled_model UI mapping attribute |
| **add_view** | `view: ft.View` | `None` | adds a Flet view control to the page views |
| **make_view** | `view_model: UIViews` | `ft.View` | generates a Flet view control from a `UIViews` type |
## UI Format
### Main UI File:
```json
{
"Header":{
//Used to declare certain values
},
"Imports":[
// Used to import controls from other files
],
"Controls":[
// Used to assign controls to variables
],
"UI":[
// Used to define route views
]
}
```
This format separates the header data, imports, controls and display UI.
- #### Header:
Headers is primarily map based and thus requires one to use keys and values unlike the list based forms like the rest are.
The keys in this block consists of:
- #### **import_folder**:
| Value Type | Example |
| ---------- | --------- |
| `str` | `"extra"` |
stores the name of the folder which contains the FJML imports
- #### **program_name**:
| Value Type | Example |
| ---------- | --------------- |
| `str` | `"Hello World"` |
stores the name of the program
- #### **style_sheet_name**:
| Value Type | Example |
| ---------- | --------------- |
| `str` | `"style_sheet"` |
Stores the name of the FJML style sheet.
- #### **action_import**:
| Value Type | Example |
| ------------- | -------------------------------- |
| `dt.JsonDict` | `{"from":"...", "import":"..."}` |
This dictionary imports the action class using the format:
| Key | Value Type | Example |
| ---------- | ---------- | --------------------- |
| **from** | `str` | `".import_path.func"` |
| **import** | `str` | `"Action"` |
full example:
```json
{
"action_import":{
"from":".import_path.func",
"import":"Action"
}
}
```
The `action_import` key's value is equivalent to:
-
```python
from .import_path.func import Action
```
The import statement is run as if it was run in your main file.
- #### **extensions**:
| Value Type | Example |
| ----------------------- | ------------------------------------------------------ |
| `Sequence[dt.JsonDict]` | `[{"from":"...", "import":"...", "using":"..."}, ...]` |
The value of this key consists of using a sequence of dictionaries which help import multiple controls at once:
| Key | Value Type | Example |
| ---------- | --------------------------- | --------------------------------------------- |
| **from** | `str` | `.custom_controls` |
| **import** | `Union[str, Sequence[str]]` | `"CustomBtn"` or `["CustomBtn", "CustomTxt"]` |
| **using** | `Optional[str]` | `"CC"` |
full example:
```json
{
"extensions":[
{
"from":".custom_controls",
"import":["CustomBtn", "CustomTxt"],
"using":"CC"
}
]
}
```
Using extension imports like this is equivalent to:
- With the `using` key:
-
```python
from . import custom_controls as CC
from CC import CustomBtn, CustomTxt
```
The use of these controls in FJML code will now have to use controls like so: `CC.CustomBtn`
- Without the `using` key:
-
```python
from .custom_controls import CustomBtn, CustomTxt
```
- #### Imports:
Imports are called using the file name of the UI file defined inside the import folder defined by the key `"source"`. If the import folder includes different folders the use of the key `"folder"` can be used to indicate the specific folder inside the main import folder where you want to import from. e.g:
- `{"source:"container_ui"}`
- `{source:["user_ui", "admin_ui"], "folder":"person_ui_folder"}`
- #### Controls:
controls can be named using the `"var_name"` key and then can be called and used in the python `"Action"` class using `"self.name_text"` or in another control using a dictionary using the `"refs"` key and the control name as its value. e.g: `{"refs":"name_text"}`
Format example:
```json
{
"var_name":"foo",
"control_type":"imported/registered control name",
"settings":{
...
}
}
```
- #### UI:
The UI section is used to define the route views used by you program.
These views use the format of:
```json
{
"route":"/Home",
"settings":{
//any view settings needed. P.S. the route parameter will always be ignored if set in the settings block.
}
}
```
and are contained in a Sequence
### Imported UI File:
With imports the JSON structure is similar except that it only has the `"Controls"` container. Using controls from other files is still possible once all dependencies are also imported into the main file.
Imported file format:
```json
{
"Controls":[]
}
```
### Style Sheet File:
With style sheets you are able to create styles for use later in your program. You are able to section off your styles by names and sub-names and thus call them using the format `{name}.{sub_name}.{sub_sub_name}...`. This format can go on forever if needed but can increase rendering time of your program if you go too deep.
Style sheet Format:
```json
{
"name_1":{
"sub_name":{
"height":200,
"width":500
}
},
"name_2":{
"sub_name":{
"height":200,
"width":500
}
}
}
```
styles can be used by then adding the `"_unpack"` attribute inside the control's `"settings"` dictionary with the dictionary formats:
- `{"styles":"{name}.{sub-name}"}`
- or `{"styles":"{name}.{sub-name} {name1}.{sub_name}"}` if multiple styles are needed
## Other FJML UI features include
- ### Calling functions and objects:
```python
class Action(EventContainer):
def _imports(self) -> None:
#register callable object
self.object_bucket.set_object("calc_width", self.calc_width)
def calc_width(self, height: int) -> int:
return height*2
```
```json
// call object
{
"control_type":"Container",
"settings":{
"width":{
"call":"calc_width",
"settings":{
"height":200
}
}
}
}
```
- ### UI loops:
```json
{
"control_type":"Column",
"settings":{
"controls":{
"control_type":"loop",
"depth":1,
"iterator":[1,2,3,4,5],
"control":{
"control_type":"Text",
"settings":{
"value":{
"control_type":"loop_index",
"idx":[0]
}
}
}
}
}
}
```
- ### Adding control to variables:
```json
{
"var_name":"name", //<- Here
"control_type":"Text",
"settings":{
"value":"John Doe",
"size":18
}
}
```
this can be accessed inside the Actions class using `self.name` and if control is defined as `self.name` inside Actions it can be called in FJML using `{"refs":"name"}`
- ### Using variables:
Allows the use of FJML variables to be referenced in the same file or else where without the need for constant importing
#### control variables:
```json
{
"var_name":"name", //<- Here
"control_type":"Text",
"settings":{
"value":"John Doe",
"size":18
}
}
{
"var_name":"text_container",
"control_type":"Container",
"settings":{
"content":{"refs":"name"},
"padding":6
}
}
```
#### code variables:
Allows the variables defined in python code to be accessed and used inside FJML code
```python
class Actions(EventContainer):
def _imports(self) -> None:
self.text_size: int = 16
```
```json
{
"var_name":"name", //<- Here
"control_type":"Text",
"settings":{
"value":"John Doe",
"size":{"code_refs":"text_size"}
}
}
```
#### Attribute and index calling
The `idx` key works for both dictionaries and index based sequences.
```json
{
"var_name":"name",
"control_type":"Text",
"settings":{
"value":"John Doe",
"size":18
}
}
{
"var_name":"get_display_name",
"control_type":"Text",
"settings":{
"value":{
"refs":"name",
"attr":"value"
},
"size":18
}
}
```
- #### Group chains:
```python
class TextSizes:
data: list[Union[dict[str, int], int]] = [18, {"name":16}]
class Actions(EventContainer):
def _imports(self) -> None:
self.text_sizes: TextSizes = TextSizes()
```
```json
{
"var_name":"name",
"control_type":"Text",
"settings":{
"value":"John Doe",
"size":{
"code_refs":"text_sizes",
"group":[
{"attr":"data"},
{"idx":1},
{"idx":"name"}
]
}
}
}
```
- ### Action Class:
In order to link your action class to FJML code you must import the in the `Header` container using the key, `action_import`.
- #### Example:
```json
{
"Header":{
...,
"action_import":{
"import":"Actions",
"from":".ui_test_program.func"
}
},
"Imports":[...],
"Controls":[...],
"UI":[...]
}
```
All action imports must exist in an importable path and be written as if it was run in the `main.py` file.
- ### Custom Controls:
FJML allows you multiple ways to define and add custom controls to your project.
This is done by using the `"extensions"` key inside the `"Header"`:
```json
{
"Header":{
...,
"extensions":[
{
"using":"fm",
"import":["Buttons", "Switches"],
"from":"flet_material"
}
]
},
"Imports":[...],
"Controls":[
{
"var_name":"switch",
"control_type":"fm.Switches",
"settings":{}
}
],
"UI":[...]
}
```
All imports must already be installed or exist in an importable path.
---
## Running the app
```python title="main.py"
from fjml import load_program, Compiler, data_types as dt
import flet as ft
class Paths:
PROGRAM: str = "path\\to\\program_folder"
COMPILED: str = "path\\to\\compiled_program\\compiled.fjml"
class App:
def __init__(self, compile_run: bool = False) -> None:
if not compile_run:
return
compiler: Compiler = Compiler(Paths.PROGRAM, Paths.COMPILED)
compiler.compile()
async def run(self, page: ft.Page):
page = load_program(Paths.COMPILED, page)
page.go("/")
if __name__ == "__main__":
app: App = App(compile_run=True)
ft.app(target=app.run)
```
Raw data
{
"_id": null,
"home_page": null,
"name": "fjml",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "flet, gui, markup language",
"author": null,
"author_email": "loafthecomputerphile <loafdcomputerphile@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/db/1c/7e44dc09249aeaffe7ba9b5648a3a6a77b9eb5e2e5ccc18e46f85bf0fa49/fjml-0.0.5.tar.gz",
"platform": null,
"description": "# FJML\n<img src=\"media/FJML_LOGO.png\">\n\n### FJML is a JSON based markup language which translates JSON files into Flet UI for web, mobile and desktop applications.\n\n\n# Example:\n\n```json title=\"ui.json\"\n{\n \"Header\":{\n \"program_name\":\"Example\",\n \"action_import\":{\n \"import\":\"Actions\",\n \"from\":\".path.to.func.file\"\n },\n },\n \"Controls\":[\n {\n \"var_name\":\"msg\",\n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":\"Hello World\",\n \"size\":20,\n \"color\":{\"code_refs\":\"colors\", \"attr\":\"green\"},\n \"weight\":{\n \"control_type\":\"FontWeight\",\n \"attr\":\"W_700\"\n }\n }\n },\n {\n \"var_name\":\"msg_display\",\n \"control_type\":\"Container\",\n \"settings\":{\n \"content\":{\"refs\":\"msg\"},\n \"alignment\":{\"control_type\":\"alignment.center\"},\n \"border_radius\":10,\n \"padding\":{\n \"control_type\":\"padding.symmetric\",\n \"settings\":{\"horizontal\":10, \"vertical\":8}\n },\n \"width\":200,\n \"ink\":true,\n \"ink_color\":{\"code_refs\":\"colors\", \"attr\":\"grey\"}\n }\n }\n ],\n \"UI\":[\n {\n \"route\":\"/\",\n \"settings\":{\n \"controls\":[\n {\"refs\":\"msg_display\"}\n ],\n \"horizontal_alignment\":{\"code_refs\":\"cross_align\"},\n \"vertical_alignment\":{\"code_refs\":\"main_align\"}\n }\n }\n ]\n}\n```\n\n\n```python title=\"func.py\"\nfrom fjml import data_types as dt\nimport flet as ft\n\n\nclass Colors:\n green: str = ft.colors.GREEN_600\n grey: str = ft.colors.GREY_200\n\n\nclass Actions(dt.EventContainer):\n\n def _page_setup(self):\n ...\n \n def _imports(self):\n self.colors: Colors = Colors()\n self.cross_align: str = ft.CrossAxisAlignment.CENTER\n self.main_align: str = ft.MainAxisAlignment.CENTER\n```\n\n```python title=\"main.py\"\nfrom fjml import load_program, Compiler, data_types as dt\nfrom path.to.program import Actions\nimport flet as ft\n\nclass Paths:\n PROGRAM: str = \"path\\\\to\\\\program_folder\"\n COMPILED: str = \"path\\\\to\\\\compiled_program\\\\compiled.fjml\"\n\nclass App:\n\n def __init__(self, compile_run: bool = False) -> None:\n if compile_run:\n compiler: Compiler = Compiler(Paths.PROGRAM, Paths.COMPILED)\n compiler.compile()\n \n async def run(self, page: ft.Page):\n page = load_program(Paths.COMPILED, Actions)\n page.go(\"/\")\n \n\nif __name__ == \"__main__\":\n app: App = App(compile_run=True)\n ft.app(target=app.run)\n```\n\n---\n\n## CLI Tooling:\nFJML comes with 2 CLI commands and each have specific parameters:\n- `registry` :\n\n The registry command is a categorical command which automatically modifies the registry file which contains of all Flet controls of your current Flet installation.\n | Choice | Value Type | Action |\n | ---------- | ---------- | --------------------- |\n | **delete** | `str` | deletes registry file |\n | **reset** | `str` | resets registry file |\n\n Example:\n - `fjml registry update`\n\n The reset command should be used after installation to ensure proper functioning of fjml\n\n- `make` :\n \n The make command generates an FJML folder containing all the needed files for running your project.\n make has one mandatory parameter, `--name`, and one optional parameter, `--path`.\n `--name` generates the name of your project while `--path` directs where that project is generated. If path is not entered it will use the current directory.\n\n Example:\n - `fjml make --name Hello World`\n\n---\n\n## Python Integration\n\nFJML allows the use of python code to perform actions such as API calls, function calls, etc. via the `EventContainer` Abstract Base Class.\n\n- The main format of the Actions class which inherits from the `EventContainer` looks like this:\n ```python\n from fjml.data_types import EventContainer\n\n class Actions(EventContainer):\n\n def _page_setup(self):\n '''\n a custom page setup function to initialize your page object with data\n '''\n \n def _imports(self):\n '''\n an import function used to run operations outside of the page before rendering the UI\n '''\n \n #you can then add custom functions to be used throughout the FJML code\n ```\n\n\n`EventContainer` also includes multiple built-in helper classes and functions to help create programs\n\n- ### `EventContainer` methods and classes\n - ### **client_storage**:\n #### See [Flet Page Docs](https://flet.dev/docs/cookbook/client-storage)\n\n ---\n\n - ### **session**:\n #### See [Flet Page Docs](https://flet.dev/docs/cookbook/session-storage)\n\n ---\n\n - ### **update**:\n #### equivalent to `ft.Page.update`\n\n ---\n\n - ### **page**:\n #### See [Flet Page Docs](https://flet.dev/docs/controls/page).\n\n ---\n\n - ### **dict_to_control**:\n | Name | Attributes | Return | Description |\n | ------------------- | ------------------------- | ---------------- | --------------------------------------------------------------------- |\n | **dict_to_control** | `control: dt.ControlDict` | `dt.ControlType` | Allows creating controls using FJML syntax inside the `EventContainer`. |\n\n - #### Example Usage:\n\n ```python\n \n class Actions(dt.EventContainer):\n\n def make_control(self) -> ft.Control:\n return self.dict_to_control({\n \"control_type\":\"Container\",\n \"settings\":{\n \"alignment\":{\"control_type\":\"alignment.center\"},\n \"content\":{\n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":\"Hello World\",\n \"size\":18\n }\n }\n }\n })\n ```\n\n ---\n\n - ### **group_assign**:\n | Name | Attributes | Return | Description |\n | ---------------- | ---------------------------------------------- | ------ | --------------------------------------------------------- |\n | **group_assign** | `obj: Any', 'attribute_map: Mapping[str, Any]` | `None` | allows assigning multiple attributes to an object at once |\n\n - #### Example Usage:\n\n ```python\n\n class Data:\n f_name: str\n l_name: str\n age: int\n \n class Actions(dt.EventContainer):\n\n def fill_data(self) -> Data:\n data: Data = Data()\n self.group_assign(\n data,\n {\n \"f_name\":\"John\",\n \"l_name\":\"Doe\",\n \"age\":21\n }\n )\n return data\n ```\n\n ---\n\n - ### **eval_locals**:\n #### This class's main use is to add or delete locals from the evil statement's locals parameter.\n | Methods | Attributes | Return | Description |\n | --------------- | ------------------------- | ------------------- | ----------------------------------------------------------------- |\n | **add** | `name: str`, `obj: Any` | `None` | adds an object to the eval statement's locals |\n | **delete** | `name: str` | `None` | deletes an object from the eval statement's locals |\n | **mass_add** | `data: Mapping[str, Any]` | `None` | adds multiple objects to the eval statement's locals |\n | **mass_delete** | `data: Sequence[str]` | `None` | deletes multiple objects from the eval statement's locals |\n | **data** | `None` | `Mapping[str, Any]` | returns a copy of all preset locals in the eval statement's locals |\n\n ---\n\n - ### **object_bucket**:\n\n | Methods | Attributes | Return | Description |\n | ----------------- | ------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------- |\n | **set_object** | `name: str`, `obj: AnyCallable` | `None` | adds any callable object to the bucket, so it can be called inside the UI code |\n | **call_object** | `name: str`, `kwargs: dict[str, Any]` | `Any` | calls the object with the necessary key word arguments. (used when object is called within the UI code) |\n | **delete_object** | `name: str` | `None` | deletes the object from the bucket |\n\n #### This class's main use is to register objects for use in FJML code via the \"**call**\" designator:\n * \u2800\n ```json\n {\n \"call\":\"get_text\",\n \"settings\":{\n \"index\":1\n }\n }\n ```\n \n #### If an object is not registered it can not be called but can only be referenced using a **code_refs** or the **func** designators.\n\n ---\n\n - ### **property_bucket**:\n | Methods | Attributes | Return | Description |\n | ------------ | --------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n | **add** | `name: str`, `obj: Any` | `None` | adds a property to be used as a `code_refs` inside the UI code |\n | **contains** | `name: str` | `bool` | used to check if a name is registered as property |\n | **call** | `name: str`, `operation: str`, `set_val: Any` | `None` | Uses the property operations (set, get, del) to either set an object using the set_val parameter, get by just giving the name or deletion using the del operation. |\n\n #### This class's main use is to register python functions as properties to be used as **code_refs**\n\n ---\n\n - ### **setup_functions**:\n #### This class's main use is to register functions to be called to set up what ever API, environment, etc. when the UI starts up.\n | Methods | Attributes | Return | Description |\n | ------------------ | ------------------------------------------------- | ------ | -------------------------------------- |\n | **add_func** | `func: Callable`, `parameters: Sequence[Any]` | `None` | adds a function to the class |\n | **mass_add_func** | `items: Sequence[tuple[Callable, Sequence[Any]]]` | `None` | adds multiple functions to the class |\n | **call_functions** | `None` | `None` | calls all functions added to the class |\n\n ---\n\n - ### **style_sheet**:\n #### this class is used primarily for retrieving styles set inside the style sheet. This is mainly used in the \"**_unpack**\" designator via the `{\"styling\":\"xyz\"}` mapping value.\n | Methods | Attributes | Return | Description |\n | ------------- | ----------- | ------------- | ----------------------------------------- |\n | **get_style** | `path: str` | `dt.JsonDict` | gets the style from a style sheet by name |\n\n ---\n\n - ### **view_operations**:\n #### This class is used to generate and register Flet views. Its main use is in the Flet's `Page.on_route_change` event.\n | Methods | Attributes | Return | Description |\n | ------------- | ------------------------------------------------------ | --------- | ----------------------------------------------------------- |\n | **set_view** | `route_name: str`, `view_settings: dt.ControlSettings` | `None` | adds a `UIViews` to the compiled_model UI mapping attribute |\n | **add_view** | `view: ft.View` | `None` | adds a Flet view control to the page views |\n | **make_view** | `view_model: UIViews` | `ft.View` | generates a Flet view control from a `UIViews` type |\n\n\n## UI Format\n\n### Main UI File:\n\n```json\n{\n \"Header\":{\n //Used to declare certain values\n },\n \"Imports\":[\n // Used to import controls from other files\n ],\n \"Controls\":[\n // Used to assign controls to variables\n ],\n \"UI\":[\n // Used to define route views\n ]\n}\n```\n\nThis format separates the header data, imports, controls and display UI.\n\n- #### Header:\n Headers is primarily map based and thus requires one to use keys and values unlike the list based forms like the rest are. \n The keys in this block consists of:\n \n - #### **import_folder**:\n | Value Type | Example |\n | ---------- | --------- |\n | `str` | `\"extra\"` |\n\n stores the name of the folder which contains the FJML imports\n \n - #### **program_name**:\n | Value Type | Example |\n | ---------- | --------------- |\n | `str` | `\"Hello World\"` |\n\n stores the name of the program\n\n - #### **style_sheet_name**:\n | Value Type | Example |\n | ---------- | --------------- |\n | `str` | `\"style_sheet\"` |\n \n Stores the name of the FJML style sheet.\n \n - #### **action_import**:\n | Value Type | Example |\n | ------------- | -------------------------------- |\n | `dt.JsonDict` | `{\"from\":\"...\", \"import\":\"...\"}` |\n\n This dictionary imports the action class using the format:\n | Key | Value Type | Example |\n | ---------- | ---------- | --------------------- |\n | **from** | `str` | `\".import_path.func\"` |\n | **import** | `str` | `\"Action\"` |\n\n full example:\n ```json\n {\n \"action_import\":{\n \"from\":\".import_path.func\",\n \"import\":\"Action\"\n }\n }\n ```\n\n The `action_import` key's value is equivalent to: \n - \n ```python\n from .import_path.func import Action\n ```\n\n The import statement is run as if it was run in your main file.\n\n - #### **extensions**:\n | Value Type | Example |\n | ----------------------- | ------------------------------------------------------ |\n | `Sequence[dt.JsonDict]` | `[{\"from\":\"...\", \"import\":\"...\", \"using\":\"...\"}, ...]` |\n \n The value of this key consists of using a sequence of dictionaries which help import multiple controls at once:\n | Key | Value Type | Example |\n | ---------- | --------------------------- | --------------------------------------------- |\n | **from** | `str` | `.custom_controls` |\n | **import** | `Union[str, Sequence[str]]` | `\"CustomBtn\"` or `[\"CustomBtn\", \"CustomTxt\"]` |\n | **using** | `Optional[str]` | `\"CC\"` |\n\n full example:\n ```json\n {\n \"extensions\":[\n {\n \"from\":\".custom_controls\",\n \"import\":[\"CustomBtn\", \"CustomTxt\"],\n \"using\":\"CC\"\n }\n ]\n }\n ```\n\n Using extension imports like this is equivalent to:\n - With the `using` key:\n - \n ```python\n from . import custom_controls as CC\n from CC import CustomBtn, CustomTxt\n ```\n\n The use of these controls in FJML code will now have to use controls like so: `CC.CustomBtn`\n - Without the `using` key:\n - \n ```python\n from .custom_controls import CustomBtn, CustomTxt\n ```\n\n- #### Imports:\n Imports are called using the file name of the UI file defined inside the import folder defined by the key `\"source\"`. If the import folder includes different folders the use of the key `\"folder\"` can be used to indicate the specific folder inside the main import folder where you want to import from. e.g:\n - `{\"source:\"container_ui\"}`\n - `{source:[\"user_ui\", \"admin_ui\"], \"folder\":\"person_ui_folder\"}`\n\n- #### Controls:\n controls can be named using the `\"var_name\"` key and then can be called and used in the python `\"Action\"` class using `\"self.name_text\"` or in another control using a dictionary using the `\"refs\"` key and the control name as its value. e.g: `{\"refs\":\"name_text\"}`\n Format example:\n ```json\n {\n \"var_name\":\"foo\",\n \"control_type\":\"imported/registered control name\",\n \"settings\":{\n ...\n }\n }\n ```\n\n- #### UI:\n The UI section is used to define the route views used by you program.\n These views use the format of:\n ```json\n {\n \"route\":\"/Home\",\n \"settings\":{\n //any view settings needed. P.S. the route parameter will always be ignored if set in the settings block.\n }\n }\n ```\n and are contained in a Sequence\n\n### Imported UI File:\n\nWith imports the JSON structure is similar except that it only has the `\"Controls\"` container. Using controls from other files is still possible once all dependencies are also imported into the main file. \n\nImported file format:\n\n```json\n{\n \"Controls\":[]\n}\n```\n\n### Style Sheet File:\n\nWith style sheets you are able to create styles for use later in your program. You are able to section off your styles by names and sub-names and thus call them using the format `{name}.{sub_name}.{sub_sub_name}...`. This format can go on forever if needed but can increase rendering time of your program if you go too deep.\n\nStyle sheet Format:\n```json\n{\n \"name_1\":{\n \"sub_name\":{\n \"height\":200,\n \"width\":500\n }\n },\n \"name_2\":{\n \"sub_name\":{\n \"height\":200,\n \"width\":500\n }\n }\n}\n```\nstyles can be used by then adding the `\"_unpack\"` attribute inside the control's `\"settings\"` dictionary with the dictionary formats:\n- `{\"styles\":\"{name}.{sub-name}\"}`\n- or `{\"styles\":\"{name}.{sub-name} {name1}.{sub_name}\"}` if multiple styles are needed\n\n\n## Other FJML UI features include\n- ### Calling functions and objects: \n ```python\n class Action(EventContainer):\n\n def _imports(self) -> None:\n #register callable object\n self.object_bucket.set_object(\"calc_width\", self.calc_width)\n \n def calc_width(self, height: int) -> int:\n return height*2\n \n ```\n ```json\n // call object\n {\n \"control_type\":\"Container\",\n \"settings\":{\n \"width\":{\n \"call\":\"calc_width\",\n \"settings\":{\n \"height\":200\n }\n }\n }\n }\n \n ```\n- ### UI loops:\n ```json\n {\n \"control_type\":\"Column\",\n \"settings\":{\n \"controls\":{\n \"control_type\":\"loop\",\n \"depth\":1,\n \"iterator\":[1,2,3,4,5],\n \"control\":{\n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":{\n \"control_type\":\"loop_index\", \n \"idx\":[0]\n }\n }\n }\n }\n }\n }\n \n ```\n\n- ### Adding control to variables:\n ```json\n {\n \"var_name\":\"name\", //<- Here\n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":\"John Doe\",\n \"size\":18\n }\n }\n ```\n this can be accessed inside the Actions class using `self.name` and if control is defined as `self.name` inside Actions it can be called in FJML using `{\"refs\":\"name\"}`\n\n- ### Using variables:\n\n Allows the use of FJML variables to be referenced in the same file or else where without the need for constant importing\n\n #### control variables:\n \n ```json\n {\n \"var_name\":\"name\", //<- Here\n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":\"John Doe\",\n \"size\":18\n }\n }\n {\n \"var_name\":\"text_container\",\n \"control_type\":\"Container\",\n \"settings\":{\n \"content\":{\"refs\":\"name\"},\n \"padding\":6\n }\n }\n ```\n\n #### code variables:\n\n Allows the variables defined in python code to be accessed and used inside FJML code\n\n ```python\n class Actions(EventContainer):\n\n def _imports(self) -> None:\n self.text_size: int = 16\n ```\n\n ```json\n {\n \"var_name\":\"name\", //<- Here\n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":\"John Doe\",\n \"size\":{\"code_refs\":\"text_size\"}\n }\n }\n ```\n\n #### Attribute and index calling\n\n The `idx` key works for both dictionaries and index based sequences.\n\n ```json\n {\n \"var_name\":\"name\", \n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":\"John Doe\",\n \"size\":18\n }\n }\n {\n \"var_name\":\"get_display_name\",\n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":{\n \"refs\":\"name\",\n \"attr\":\"value\"\n },\n \"size\":18\n }\n }\n ```\n \n - #### Group chains:\n \n ```python\n \n class TextSizes:\n data: list[Union[dict[str, int], int]] = [18, {\"name\":16}]\n \n \n class Actions(EventContainer):\n def _imports(self) -> None:\n self.text_sizes: TextSizes = TextSizes()\n\n ```\n\n ```json\n {\n \"var_name\":\"name\",\n \"control_type\":\"Text\",\n \"settings\":{\n \"value\":\"John Doe\",\n \"size\":{\n \"code_refs\":\"text_sizes\",\n \"group\":[\n {\"attr\":\"data\"},\n {\"idx\":1},\n {\"idx\":\"name\"}\n ]\n }\n }\n }\n ```\n- ### Action Class:\n In order to link your action class to FJML code you must import the in the `Header` container using the key, `action_import`.\n - #### Example:\n\n ```json\n {\n \"Header\":{\n ...,\n \"action_import\":{\n \"import\":\"Actions\",\n \"from\":\".ui_test_program.func\"\n }\n },\n \"Imports\":[...],\n \"Controls\":[...],\n \"UI\":[...]\n }\n ```\n\n All action imports must exist in an importable path and be written as if it was run in the `main.py` file.\n\n\n- ### Custom Controls:\n FJML allows you multiple ways to define and add custom controls to your project.\n This is done by using the `\"extensions\"` key inside the `\"Header\"`:\n\n ```json\n {\n \"Header\":{\n ...,\n \"extensions\":[\n {\n \"using\":\"fm\",\n \"import\":[\"Buttons\", \"Switches\"],\n \"from\":\"flet_material\"\n }\n ]\n },\n \"Imports\":[...],\n \"Controls\":[\n {\n \"var_name\":\"switch\",\n \"control_type\":\"fm.Switches\",\n \"settings\":{}\n }\n ],\n \"UI\":[...]\n }\n ```\n\n All imports must already be installed or exist in an importable path.\n\n---\n\n## Running the app\n \n```python title=\"main.py\"\nfrom fjml import load_program, Compiler, data_types as dt\nimport flet as ft\n\nclass Paths:\n PROGRAM: str = \"path\\\\to\\\\program_folder\"\n COMPILED: str = \"path\\\\to\\\\compiled_program\\\\compiled.fjml\"\n\nclass App:\n\n def __init__(self, compile_run: bool = False) -> None:\n if not compile_run:\n return\n \n compiler: Compiler = Compiler(Paths.PROGRAM, Paths.COMPILED)\n compiler.compile()\n \n async def run(self, page: ft.Page):\n page = load_program(Paths.COMPILED, page)\n page.go(\"/\")\n\nif __name__ == \"__main__\":\n app: App = App(compile_run=True)\n ft.app(target=app.run)\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "A JSON based markup language which translates JSON files into Flet UI",
"version": "0.0.5",
"project_urls": {
"Homepage": "https://github.com/loafthecomputerphile/fjml",
"Issues": "https://github.com/loafthecomputerphile/fjml/issues"
},
"split_keywords": [
"flet",
" gui",
" markup language"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "9452613d5f4a494f51002064bcd47000296ea311480874bf7d7d35d29a57800e",
"md5": "5b51c6380b9f2a2586272c8c42cd83a2",
"sha256": "2faebb6b5f345c6fb8a668b8b51f156557c8b07dae38aa4d127f85481496ea60"
},
"downloads": -1,
"filename": "fjml-0.0.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5b51c6380b9f2a2586272c8c42cd83a2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 44095,
"upload_time": "2024-08-08T21:32:23",
"upload_time_iso_8601": "2024-08-08T21:32:23.949581Z",
"url": "https://files.pythonhosted.org/packages/94/52/613d5f4a494f51002064bcd47000296ea311480874bf7d7d35d29a57800e/fjml-0.0.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "db1c7e44dc09249aeaffe7ba9b5648a3a6a77b9eb5e2e5ccc18e46f85bf0fa49",
"md5": "976e68d8b93e4f1a26354b15dfbae1a1",
"sha256": "6e8124131281589241c08039b32e7aaf68ea7a9098c064cc435378fda5aa1cbb"
},
"downloads": -1,
"filename": "fjml-0.0.5.tar.gz",
"has_sig": false,
"md5_digest": "976e68d8b93e4f1a26354b15dfbae1a1",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 43507,
"upload_time": "2024-08-08T21:32:25",
"upload_time_iso_8601": "2024-08-08T21:32:25.521940Z",
"url": "https://files.pythonhosted.org/packages/db/1c/7e44dc09249aeaffe7ba9b5648a3a6a77b9eb5e2e5ccc18e46f85bf0fa49/fjml-0.0.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-08 21:32:25",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "loafthecomputerphile",
"github_project": "fjml",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "dill",
"specs": [
[
"==",
"0.3.8"
]
]
},
{
"name": "flet",
"specs": [
[
"==",
"0.23.2"
]
]
},
{
"name": "typing_extensions",
"specs": [
[
"==",
"4.12.2"
]
]
}
],
"lcname": "fjml"
}