# NUI setup

This guide will help you to set up the emote wheel in the NUI (not the emotes itself, see [README.md](readme) for this).

This might be new for you: Because to set up the emote wheel it would be helpful if you know something about the _JavaScript_ programming language. But don't worry, even if JavaScript doesn't mean anything to you. We have collected some examples. You can copy the examples and adapt, duplicate and extend them as you like.

***

## Why (the fuck) JavaScript?

**In short:**

Because we think it's better that way ;)

**In more detail:**

NUI stands for _Network User Interface_ and is a way to display a user interface in the game. This is done via a web browser as overlay in the game. This web browser is called _CEF_ (_Chromium Embedded Framework_) - or in simple words some version of _Google Chrome_.

Anyway, that's why the NUI is basically based on web pages. Web pages are declared in _HTML_ (Hyper Text Markup Language), beautified by _CSS_ (Cascading Style Sheets) and brought to life by _JavaScript_. That's where you come in. The emote wheel can be very complex even bigger it grows. This will be too complicated via _Lua_ configuration file. Transferring the emote wheel configuration from the client to the NUI can also be very time-consuming. So we have decided to use directly a _JavaScript_ file for this.

***

## Why (the fuck) `*.demo.js` files?

**In short:**

To prevent overwriting your config files each time the resource is updated.

***

## Debugging

No one is safe from mistakes. So sometimes during "writing" (coding) the configuration, something may go wrong. In this case you can use the _Developer Tools_ of the browser to debug the NUI. Open the _REDM_ console via `F8` and choose `Tools` > `NUI` > `Open DevTools` from the context menu. If the game is running, you will see the _Developer Tools_ of the NUI. There you can see the _Console_ tab. The _Console_ tab is the place where you can see the errors and warnings of the NUI.

***

## Create `config.js`

If you set up the resource the first time there is no `config.js` file. Go into the folder `html_nss_emotes` and copy `config.demo.js` to `config.js`. Now you can start with the configuration.

**Why is there a `config.demo.js` file?**

This may seem unusual to you. But to prevent that the configuration is accidentally overwritten during updates, there is a demo configuration. The demo configuration may contain new features during updates and serves as a blueprint.

***

## Basic `config.js` format

The `config.js` file is a _JavaScript_ file. In detail, it is a _JavaScript_ module. Modules can be imported by other modules (which the emote wheel module do). The following is the basic structure of the `config.js` file:

```javascript
import {NssEmotesConfig} from "./Classes/NssEmotesConfig.js";

const config = new NssEmotesConfig();
// DO NOT TOUCH THE LINES ABOVE

// DO YOUR CONFIGURATION HERE

// DO NOT TOUCH THE LINES BELOW
export {config}
```

**Important:** The lines before `// DO NOT TOUCH THE LINES ABOVE` and after `// DO NOT TOUCH THE LINES BELOW` are mandatory and must not be touched.

`// DO YOUR CONFIGURATION HERE` is the place where you can start your configuration. You can add as many lines as you want and as many lines as you need.

**What is the `config` object?**

`config` is an object (in detail it is an instance of the class `NssEmotesConfig`) that contains all the configuration for the NUI of the emote wheel. This object has so-called _methods_ that can be called to configure the emote wheel. The methods are described in the following sections.

**What are the other `*.demo.js` files for?**

The other `*.demo.js` files are demo files with prepared configurations like emotes or walk styles. You will find more information about this in the `config.demo.js` (or `config.js`) file.

***

## Icons

Wheel buttons can have icons. These icons must be placed in the `html_nss_emotes/icons` folder.

We do not allow the use of icons from external resources. This is to prevent your players from having to download external resources (which can be a security risk). If the icons are stored locally in the resource the loading times are faster.

We recommend using the _SVG_ format for the icons. This format is very small and can be scaled without loss of quality. It has also an alpha channel (transparency) and can be colored with _CSS_. Additionally, _PNG_ files can be used, too.

***

## Languages

Not implemented currently.

***

## Key bindings

The emote wheel can be opened with a key binding but this is part of the configuration in the `config.lua` file.

With the following code you can define all keys for the NUI emote wheel:

```javascript
config.defineCloseKeys('X', 'Escape', 'Backspace'); // You can define as many keys as you want
config.defineWheelBackKey('rmb', 'mouse4', 'ArrowUp'); // You can combine keyboard keys and mouse buttons
config.defineSearchKey('s');
config.defineInventoryKeys('i');
config.defineOptionsKeys('o');
config.defineDialogCloseKeys('x', 'Backspace');
config.defineDialogBackKeys('rmb', 'mouse4', 'Escape');

config.defineCancelAnimKey('c');
config.defineCancelAnimCommand('actstop'); // The command that is executed when the cancel animation key is pressed
```

See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key\_Values for available keyboard keys.

Available mouse buttons are:

* `lmb` (left mouse button)
* `scroll` (mouse wheel)
* `rmb` (right mouse button)
* `mouse4` (mouse button 4, in most cases the back button on the mouse)

**Important:**

* The key bindings are case-insensitive. So `x` is the same as `X`.
* Numbers are not allowed as key bindings because 0-9 are used for the hotbar buttons.

***

## UI Options

The emote wheel has some options that can be configured. The following code shows the default values of the options:

```javascript
config.defineDefaultSfxVolumeInPercent(100); // Value between 0 and 100, steps in 10
config.defineDefaultBgFx('WheelHUDIn'); // See Config.BackgroundFxList in config.lua for available values
```

***

## Colors

The emote wheel can be customized with colors. The following code set up the default colors of the emote wheel:

```javascript
// Optional: Emote wheel colors
config.defineDefaultWheelBgColor('#000000'); // Black
config.defineDefaultWheelHoverColor('#990000'); // Dark red
config.defineDefaultWheelClickColor('#ffffff'); // White

// Optional: Hotbar colors
config.defineDefaultHotbarBgColor('#000000'); // Black
config.defineDefaultHotbarHoverColor('#990000'); // Dark red
config.defineDefaultHotbarClickColor('#ffffff'); // White
```

The colors are defined as _CSS_ hex colors.

**Important:** Custom colors of emote wheel buttons will not be applied to the hotbar buttons on assignment.

***

## Root wheel

The root wheel is the "highest" wheel (like a folder) that is displayed when the NUI is opened. The root wheel has to be created first and can be customized with the following code:

```javascript
// Creates the root wheel saved in the variable "root_wheel". You can rename the variable as you want.
const root_wheel = config.createRootWheel();

// Sets the label of the root wheel OR ...
root_wheel.setLabel('Home');

// ..sets an image for the root wheel (image hides label).
root_wheel.setImage('your-logo-name.png'); // The image must be placed in the "html_nss_emotes/logos" folder. If the folder does not exist, create it.

// The following settings are each optional if you want to defer them to the default settings
root_wheel.setBgColor('#000099'); // Dark blue
root_wheel.setHoverColor('#009900'); // Dark green
root_wheel.setClickColor('#00ffff'); // Cyan
```

`config.createRootWheel()` creates a new object that represents the configuration of the root wheel. This object has methods that can be called to configure the root wheel. In the example above we save the object in the variable `root_wheel` which we can use later to configure the root wheel settings or add buttons to the root wheel.

Tip for wheel images via `setImage()`:

* Use high resolution images.
* Use a transparent background.
* Use a square image (e.g. 512x512 pixels or higher) but a rounded logo!

Pro-tip: Make it short via chaining!

Chaining is possible for almost all methods.

```javascript
const root_wheel = config.createRootWheel().setLabel('Home').setBgColor('#000099').setHoverColor('#009900').setClickColor('#00ffff'); // Don't forget the semicolon!
```

or

```javascript
const root_wheel = config.createRootWheel()
    .setLabel('Home')
    .setBgColor('#000099')
    .setHoverColor('#009900')
    .setClickColor('#00ffff'); // Don't forget the semicolon!
```

It's up to you which style you prefer.

***

## Wheel Buttons

Use the `root_wheel` (or other wheel) object to add buttons to it:

```javascript
// Creates a button object saved in the variable "drunken_walk_style_btn". You can rename the variable as you want.
const drunken_walk_style_btn = root_wheel.addButton();

// The following settings are each required.

// Choose only one of the following settings each button! You see here all available settings for example.
drunken_walk_style_btn.setCommand('drunken_walk_style'); // Command supports arguments too. Example: 'drunken_walk_style arg1'
drunken_walk_style_btn.setEventName('vorp_core:open_inventory');
drunken_walk_style_btn.setInventoryItemId('coal');

// At least the "icon" or "label" is required. You can set both if you wish.
// If a "inventory item" is used then "icon" and "label" are optional. The "icon" overrides the "inventory item" icon.
drunken_walk_style_btn.setIcon('drunken_walk_style.png'); // See chapter "Icons" for more information. Overrides the "inventory item" icon.

// You can set directly a label or use the related translation key from your language file.
drunken_walk_style_btn.setLabel('Drunken walk style'); /* OR */ drunken_walk_style_btn.setTranslationKey('WalkStyleDrunk')

// The following settings are each optional if you want to defer them to the default settings

// Colors (overrides the colors of the root wheel)
drunken_walk_style_btn.setBgColor('#000099'); // Dark blue
drunken_walk_style_btn.setHoverColor('#009900'); // Dark green
drunken_walk_style_btn.setClickColor('#00ffff'); // Cyan

// Keeps the emote wheel open after the button was clicked (works only in wheel not in hotbar or search)
drunken_walk_style_btn.setKeepOpenAfterUse();

// Restrict usage to chars:
// Only the char ids 207 and 210 can use that button
// Restrictions will be inherited to sub wheels recursively. So you have to set the restrictions only once.
// New since 1.2.0
drunken_walk_style_btn.restrictToChar('207');
drunken_walk_style_btn.restrictToChar('210');

// Restrict usage to groups:
// Only the groups admin and moderator can use that button
// Restrictions will be inherited to sub wheels recursively. So you have to set the restrictions only once.
// New since 1.2.0
drunken_walk_style_btn.restrictToGroup('admin');
drunken_walk_style_btn.restrictToGroup('moderator');

// Restrict usage to jobs:
// Only the jobs police and ambulance can use that button
// Restrictions will be inherited to sub wheels recursively. So you have to set the restrictions only once.
// New since 1.2.0
drunken_walk_style_btn.restrictToJob('police'); // All job grades of police can use that button
drunken_walk_style_btn.restrictToJob('ambulance', 2); // Only the job grade 2 and higher of ambulance can use that button
```

Here an example with chaining and more buttons (without custom colors):

```javascript
root_wheel.addButton().setLabel('Drunken walk style').setCommand('drunken_walk_style').setIcon('drunken_walk_style.png').restrictToGroup('admin');
root_wheel.addButton().setLabel('Hurt walk style').setCommand('hurt_walk_style').setIcon('hurt_walk_style.png');
root_wheel.addButton().setLabel('Injured walk style').setCommand('injured_walk_style').setIcon('injured_walk_style.png').restrictToChar('207').restrictToChar('210');
root_wheel.addButton().setLabel('Injured walk style 2').setCommand('injured_walk_style_2').setIcon('injured_walk_style_2.png');
root_wheel.addButton().setLabel('Happy walk style').setCommand('happy_walk_style').setIcon('happy_walk_style_3.png').restrictToJob('sheriff', 2);
```

This is much shorter than the previous example. It is not necessary to save the buttons in variables because they are not needed later.

### Button types

* **Command** buttons, e.g. `setCommand('drunken_walk_style');`, can be used to trigger chat/console commands including arguments.
* **Event** buttons, e.g. `setEventName('vorp_core:open_inventory');`, can be used to trigger client events.
  * Tip: To call a server event create a client event that calls the server event.
* **Inventory item** buttons, e.g. `setInventoryItem('water');`, can be used to trigger the usage of an inventory item.
  * Because we use Vorp a item related icon (existing in Vorp Inventory) will automatically be set to the button.
* Folder buttons, see chapter "Sub wheels" for more information.

***

## Sub wheels (folder buttons)

Sub wheels are wheels that are displayed when a folder button of a wheel is clicked. You can nest sub wheels as deep as you want. The folder buttons can have restrictions like the normal buttons. If a parent folder button has restrictions then the restrictions will be inherited to the sub wheels on creation.

```javascript
// First create and configure the button first like described in the chapter "Wheel Buttons" but use the 
// method "addFolderButton()" instead of "addButton()".
// Important: Folder buttons have no command!
const walk_style_folder_btn = root_wheel.addFolderButton();
walk_style_folder_btn.setLabel('Walk styles'); // Required (as short as possible to fit in the button)
walk_style_folder_btn.setIcon('walk_style.png'); // Optional (see chapter "Icons" for more information)

// Second create the sub wheel and configure it like described in the chapter "Root wheel".
// The `getWheel()` is only available for folder buttons and returns a new the wheel object.
const walk_styles_wheel = walk_style_folder_btn.getWheel();
```

**Note:**

* A folder button can only have one sub wheel (logical).
* If the sub wheel has no label then the label of its folder button is used.
* Each sub wheel can have its own colors. If the colors are not defined then the default colors will be used.

***
