diff --git a/docs_md/02-creating_custom_components.md b/docs_md/02-creating_custom_components.md index ead31b43..b7aaf993 100644 --- a/docs_md/02-creating_custom_components.md +++ b/docs_md/02-creating_custom_components.md @@ -1,18 +1,16 @@ -# Creating custom components +# Creating Custom Components ## Overview -Druid allows you to create your custom components which contains your custom logic, other Druid basic components or other custom components. +Druid offers the flexibility to create custom components that contain your own logic, as well as other Druid basic components or custom components. While Druid provides a set of predefined components like buttons and scrolls, it goes beyond that and provides a way to handle all your GUI elements in a more abstract manner. Custom components are a powerful way to separate logic and create higher levels of abstraction in your code. -I wanna make a point that Druid is not only set of defined components to place buttons, scroll, etc. But mostly it's a way how to handle all your GUI elements in general. Custom components is most powerful way to separate logic and make higher abstraction in your code. +Every component is a child of the Basic Druid component. You can call methods of basic components using `self:{method_name}`. -Every component is the children of Basic Druid component. Read the [basic component API here](https://insality.github.io/druid/modules/BaseComponent.html), Methods of basic components you can call via `self:{method_name}` +## Custom Components +### Basic Component Template +A basic custom component template looks like this (you can copy it from `/druid/templates/component.template.lua`): -## Custom components - -### Basic component template -Basic custom component template looks like this. It's good start to create your own component! (you can copy it from `/druid/templates/component.template.lua`) ```lua local component = require("druid.component") @@ -24,7 +22,6 @@ local SCHEME = { BUTTON = "button", } --- Component constructor. Template name and nodes are optional. Pass it if you use it in your component function Component:init(template, nodes) self:set_template(template) self:set_nodes(nodes) @@ -34,161 +31,127 @@ function Component:init(template, nodes) self.button = self.druid:new_button(SCHEME.BUTTON, function() end) end --- [OPTIONAL] Call on component remove or on druid:final function Component:on_remove() end return Component ``` -### Full component template +### Full Component Template + +A full custom component template looks like this (you can copy it from `/druid/templates/component_full.template.lua`): -Full custom component template looks like this (you can copy it from `/druid/templates/component_full.template.lua`: ```lua local component = require("druid.component") ---@class component_name : druid.base_component local Component = component.create("component_name") --- Scheme of component gui nodes local SCHEME = { - ROOT = "root", - BUTTON = "button", + ROOT = "root", + BUTTON = "button", } --- Component constructor. Template name and nodes are optional. Pass it if you use it in your component function Component:init(template, nodes) - -- If your component is gui template, pass the template name and set it - self:set_template(template) - -- If your component is cloned my gui.clone_tree, pass nodes to component and set it - self:set_nodes(nodes) - - -- self:get_node will auto process component template and nodes - self.root = self:get_node(SCHEME.ROOT) - -- Use inner druid instance to create components inside this component - self.druid = self:get_druid() + self:set_template(template) + self:set_nodes(nodes) + self.root = self:get_node(SCHEME.ROOT) + self.druid = self:get_druid() end --- [OPTIONAL] Call every update step function Component:update(dt) end --- [OPTIONAL] Call default on_input from gui script function Component:on_input(action_id, action) return false end --- [OPTIONAL] Call on component creation and on component:set_style() function function Component:on_style_change(style) end --- [OPTIONAL] Call default on_message from gui script function Component:on_message(message_id, message, sender) end --- [OPTIONAL] Call if druid has triggered on_language_change function Component:on_language_change() end --- [OPTIONAL] Call if game layout has changed and need to restore values in component function Component:on_layout_change() end --- [OPTIONAL] Call if game window size is changed function Component:on_window_resized() end --- [OPTIONAL] Call, if input was capturing before this component --- Example: scroll is start scrolling, so you need unhover button function Component:on_input_interrupt() end --- [OPTIONAL] Call, if game lost focus function Component:on_focus_lost() end --- [OPTIONAL] Call, if game gained focus function Component:on_focus_gained() end --- [OPTIONAL] Call on component remove or on druid:final function Component:on_remove() end return Component ``` +### Spawning a Custom Component -### Spawn custom component +After creating your custom component, you can spawn it in your code. For example, if you have a component named `my_component`, you can create it like this: -After the creating your custom component, you now able to create it. - -For example we made the component `my_component`. Now we able create it like this: ```lua local druid = require("druid.druid") local my_component = require("my.amazing.component") function init(self) - self.druid = druid.new(self) - self.druid:new(my_component, "template_name", nodes) + self.druid = druid.new(self) + self.druid:new(my_component, "template_name", nodes) end ``` -The template name - is the name of GUI template file if you use it in your custom component. -The nodes - is table from `gui.clone_tree(node)`. If you spawn multiply nodes for component, pass it to component constructor. -Inside component you have to set template and nodes via -`self:set_template(template)` and `self:set_nodes(nodes)` - +In the code above, `template_name` refers to the name of the GUI template file if you're using it in your custom component. `nodes` is a table obtained from `gui.clone_tree(node)`. If you're spawning multiple nodes for the component, pass the table to the component constructor. Inside the component, you need to set the template and nodes using `self:set_template(template)` and `self:set_nodes(nodes)`. -### Register custom component +### Registering a Custom Component -You can register your custom component for use it without require component module in every file. Registering components is comfortable for very basic components in your game. - -Add your custom component to druid via `druid.register +You can register your custom component to use it without requiring the component module in every file. Registering components is convenient for very basic components in your game. Here's how you can register a custom component in Druid: ```lua local druid = require("druid.druid") local my_component = require("my.amazing.component") function init(self) - druid.register("my_component", my_component) + druid.register("my_component", my_component) end ``` -Registering make new function with "new_{component_name}". In our example it will be: `druid:new_my_component()`. +Once the component is registered, a new function will be available with the name "new_{component_name}". In our example, it will be `druid:new_my_component()`. With the component registered, you can create an instance of it using the following code: -As component registered, you can create your component with next code: ```lua local druid = require("druid.druid") local my_component = require("my.amazing.component") function init(self) - self.druid = druid.new(self) - self.my_component = self.druid:new_my_component(template, nodes) + self.druid = druid.new(self) + self.my_component = self.druid:new_my_component(template, nodes) end ``` +## Create Druid Component Editor Script -## Create Druid Component editor script - -The Druid has editor script to help you with creating lua file for your GUI scene. -The commands is available on *.gui scenes in menu `Edit -> Create Druid Component` - -The script will check current GUI scene and generate lua file with all Druid component stubs. The output file will be named as current GUI scene and placed nearby. The *.lua file should be not exists, the script will not override any file. If you want to re-generate file, delete previous one first. +Druid provides an editor script to assist you in creating Lua files for your GUI scenes. You can find the commands under the menu `Edit -> Create Druid Component` when working with *.gui scenes. -The script required `python3` with `deftree` installed. If `deftree` is not installed the instructions will be prompt in console. +The script analyzes the current GUI scene and generates a Lua file with stubs for all Druid components found. The output file is named after the current GUI scene and placed in the same directory. Note that the script does not override any existing *.lua files. If you want to regenerate a file, delete the previous version first. +The script requires `python3` with `deftree` installed. If `deftree` is not installed, the instructions will be displayed in the console. -### Auto layout components +### Auto-Layout Components -The generator script also check current GUI scene for Druid components to make stubs for them. The script will check the node names and if it starts with special keyword it will make component stubs in generated lua file. It will generate component declaring, callback functions stubs and annotations. - -Start your node names with one of next keyword to say parser make component stubs for your. For example for nodes `button` and `button_exit` will be generated two Druid Button components with callback stubs. +The generator script also checks the current GUI scene for Druid components and creates stubs for them. If a node name starts with a specific keyword, the script generates component stubs in the Lua file. For example, nodes named `button` and `button_exit` will result in the generation of two Druid Button components with callback stubs. Available keywords: -- `button` - add [Druid Button](01-components.md#button) and generate callback stub -- `text` - add [Druid Text](01-components.md#text) -- `lang_text` - add Druid [Druid Lang Text](01-components.md#lang-text) -- `grid` or `static_grid` - add Druid [Druid Static Grid](01-components.md#static-grid). You should to setup Grid prefab for this component after file generation -- `dynamic_grid` - add Druid [Druid Dynamic Grid](01-components.md#dynamic-grid) -- `scroll_view` - add [Druid Scroll](01-components.md#scroll). It will add `scroll_content` node with the same postfix too. Check that is will correct node -- `blocker` - add [Druid Blocker](01-components.md#blocker) -- `slider` - add [Druid Slider](01-components.md#slider). You should to adjust end position of Slider after file generation -- `progress` - add [Druid Progress](01-components.md#progress) -- `timer` - add [Druid Timer](01-components.md#timer) - +- `button`: Adds a [Druid Button](01-components.md#button) component and generates the callback stub. +- `text`: Adds a [Druid Text](01-components.md#text) component. +- `lang_text`: Adds a [Druid Lang Text](01-components.md#lang-text) component. +- `grid` or `static_grid`: Adds a [Druid Static Grid](01-components.md#static-grid) component. You should set up the Grid prefab for this component after generating the file. +- `dynamic_grid`: Adds a [Druid Dynamic Grid](01-components.md#dynamic-grid) component. +- `scroll_view`: Adds a [Druid Scroll](01-components.md#scroll) component. It also adds a `scroll_content` node with the same postfix. Ensure that it's the correct node. +- `blocker`: Adds a [Druid Blocker](01-components.md#blocker) component. +- `slider`: Adds a [Druid Slider](01-components.md#slider) component. You should adjust the end position of the Slider after generating the file. +- `progress`: Adds a [Druid Progress](01-components.md#progress) component. +- `timer`: Adds a [Dr +uid Timer](01-components.md#timer) component. -## Best practice on custom components +## Best Practices for Custom Components -On each component recommended describe component scheme in next way: -To get this structure, Druid has editor script to help you with it. Select your GUI nodes in editor outline, right click and press "Print GUI Scheme". And copy the result from the output console. +When working with each component, it's recommended to describe the component scheme in the following way: ```lua -- Component module @@ -197,27 +160,22 @@ local component = require("druid.component") local M = component.create("your_component") local SCHEME = { - ROOT = "root", - ITEM = "item", - TITLE = "title" + ROOT = "root", + ITEM = "item", + TITLE = "title" } function M.init(self, template_name, node_table) - self:set_template(template_name) - self:set_nodes(node_table) - - -- helper can get node from gui/template/table - local root = self:get_node(SCHEME.ROOT) - -- This component can spawn another druid components: - local druid = self:get_druid() - -- Button self on callback is self of _this_ component - local button = druid:new_button(...) -end + self:set_template(template_name) + self:set_nodes(node_table) -``` + local root = self:get_node(SCHEME.ROOT) + local druid = self:get_druid() -## Power of using templates + -- Create components inside this component using the inner druid instance +end +``` -You can use one component, but creating and customizing templates for them. Templates only requires to match the component scheme. +## The Power of Using Templates -For example you have component `player_panel` and two GUI templates: `player_panel` and `enemy_panel` with different layout. But the same component script can be used for both of them. +With Druid, you can use a single component but create and customize templates for it. Templates only need to match the component scheme. For example, you can have a component named `player_panel` and two GUI templates named `player_panel` and `enemy_panel` with different layouts. The same component script can be used for both templates. diff --git a/docs_md/FAQ.md b/docs_md/FAQ.md index 62116664..4812a914 100644 --- a/docs_md/FAQ.md +++ b/docs_md/FAQ.md @@ -1,67 +1,36 @@ - # Druid FAQ ->_Have questions about Druid? Ask me!_ -> _Here is questions you might have_ - -### Q: Why I want use Druid? -**A:** --- - - -### Q: How to remove the Druid component instance? -**A:** Any created **Druid** component can be removed with _druid:remove_. [API reference link](https://insality.github.io/druid/modules/druid_instance.html#druid:remove). - - -### Q: How to make scroll work? -**A:** --- - - -### Q: How the input is processing? -**A:** -*SImply*: the **Druid** has a LIFO queue to check input. Last added buttons have more priority than first. Placing your buttons from behind to the front is correct in most cases. - +Welcome to the Druid FAQ! Here are answers to some common questions you may have: -### Q: For what purpose Blocker component is exist? -**A:** Component explanation [here](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#notes-2). -With Blocker you can block input in some zone. It is useful for make unclickable zone in buttons or kind of buttons panel on other big button (ex. close windows on window background click) +### Q: How do I remove a Druid component instance? +**A:** To remove a created Druid component, use the `druid:remove` function. You can find more information in the [API reference](https://insality.github.io/druid/modules/druid_instance.html#druid:remove). +### Q: How does Druid process input? +**A:** Input processing in Druid follows a Last-In-First-Out (LIFO) queue. Buttons added later have higher priority than those added earlier. To ensure correct button behavior, place your buttons from back to front in most cases. -### Q: Which stuff can I do with custom components? -**A:** Any of you can imagine! There is a lot of examples, but in general: custom components allow you place component and some game logic separately from other stuff. It will be reusable, easier for testing and developing. +### Q: What is the purpose of the Blocker component? +**A:** The Blocker component is used to block input in a specific zone. It is useful for creating unclickable zones within buttons or for creating a panel of buttons on top of another button (e.g., closing windows by clicking on the window background). You can find more information about the Blocker component [here](https://github.com/Insality/druid/blob/master/docs_md/01-components.md#notes-2). -For example it can be element in scroll with buttons, your custom GUI widget or even component with your game logic. Usually custom components going with templates. You can do several templates for single component module (for different visuals!) +### Q: What can I do with custom components? +**A:** With custom components in Druid, the possibilities are endless! Custom components allow you to separate component placement and game logic from other elements, making them reusable and easier to test and develop. Custom components can be used for scroll elements with buttons, custom GUI widgets, or even components with custom game logic. Templates often accompany custom components, allowing you to create multiple visual variations for a single component module. You can find some examples of custom components [here](https://github.com/Insality/druid-assets). -Some examples of custom components you can find [here](https://github.com/Insality/druid-assets). +### Q: How does `self:get_node()` work? +**A:** The `self:get_node()` function in a Druid component searches for nodes in the GUI directly or in cloned nodes created using `gui.clone_tree()`. It also considers nodes placed as templates, with the full node ID composed of the template name and node name (including cloned nodes). To ensure correct usage of `self:get_node()`, set up the component nodes using `self:set_template()` and `self:set_component_nodes()` before calling `self:get_node()`. It's best to pass the string name of the node, rather than the GUI node itself. - -### Q: How *self:get_node()* is working? -**A:** The node can be placed in gui directly or can be cloned via *gui.clone_tree()*. Also nodes can be placed as templates, so full node id will be composed from template name and node name (in cloned nodes too). - -**Druid** component *self:get_node()* trying to search in all of this places. Use *self:set_template()* and *self:set_component_nodes()* for correct setup component nodes before any call of *self:get_node()*. - -Remember, usually you should pass *__string name__ of the node*, not gui node itself. It's better and more druid-way. - - -### Q: My button in scroll is clickable outside the stencil node -**A:** Since **Druid** checking click node with _gui.pick_node_, stencil is not prevent this. You can setup additional click zone on your buttons with _button:set_click_zone_. - -The usual Druid way after add button to the scroll do: +### Q: My button in a scroll is clickable outside the stencil node. How can I fix this? +**A:** When using Druid, the stencil node does not prevent buttons from being clickable outside its bounds. To address this, you can set up an additional click zone on your buttons using the `button:set_click_zone()` function. After adding a button to the scroll, you can use the following code: ```lua --- Scroll view node usually is stencil node +-- Assuming the scroll view node is the stencil node button:set_click_zone(scroll.view_node) ``` - -### Q: How to use EmmyLua annotations? _(from Druid 0.6.0)_ -**A:** Since the dependencies can't be processed by external editors, for use generated EmmyLua annotations you should copy the _druid/annotations.lua_ to your project. For EmmyLua it will be enough. Remember you can _restart emmylua server_ for refresh the changes, if something goes wrong. -After the annotations is processed, you should point the type of Druid in requires: +### Q: How do I use EmmyLua annotations? (from Druid 0.6.0) +**A:** EmmyLua annotations are used for better autocompletion and type inference in editors. To use the generated EmmyLua annotations, copy the `druid/annotations.lua` file to your project. After copying, you may need to restart the EmmyLua server to ensure the changes take effect. Once the annotations are processed, you can specify the type of Druid in your code: ```lua ---@type druid local druid = require("druid.druid") --- Now the autocomplete is working +-- Autocomplete and type information should now work ``` - -### Q: When I should use *on_layout_change*? -**A:** --- +Feel free to ask any additional questions you have about Druid!