imperazim/libform

Form library for PocketMine plugins

v1.0.0 2025-06-03 16:41 UTC

This package is auto-updated.

Last update: 2025-06-03 19:03:45 UTC


README

Form Library for PocketMine (Minecraft PE)

Overview

LibForm is a PHP library that simplifies the creation of Minecraft forms in PocketMine. It offers two approaches:

  1. Class-based
    Extend abstract classes to define form structure, elements, and behavior. Passing true as the third constructor argument automatically sends the form to the player.

  2. Dynamic (Fluent Interface)
    Build forms on-the-fly using method chaining. Ideal for quick, concise form creation without defining separate classes.

Supported form types:

  • List Form (LongForm)
  • Modal Form
  • Custom Form

Installation

Add LibForm to your project with Composer:

composer require imperazim/libform

Then include classes under the imperazim\form namespace.

Form Types

1. List Form (LongForm)

A scrollable list of buttons, optionally with custom textures or icons.

1.1. Class-based

  1. Extend LongForm

  2. Override three methods:

    • title(): returns a Title object.
    • content(): returns a Content object.
    • buttons(): returns a ButtonCollection. Each Button can have a texture and a callback via ButtonResponse.
  3. Instantiate with true to automatically send to the player.

use imperazim\form\long\LongForm;
use imperazim\form\long\elements\Button;
use imperazim\form\long\elements\ButtonTexture;
use imperazim\form\long\elements\ButtonCollection;
use imperazim\form\long\response\ButtonResponse;
use imperazim\form\base\Title;
use imperazim\form\base\Content;

class MyListForm extends LongForm {
    protected function title(Player $player, FormData $formData): Title {
        return new Title('Main Menu');
    }

    protected function content(Player $player, FormData $formData): Content {
        return new Content('Select an option:');
    }

    protected function buttons(Player $player, FormData $formData): ButtonCollection {
        return ButtonCollection::fromArray([
            new Button(
                'Option 1',
                new ButtonTexture('textures/ui/icon_recipe', ButtonTexture::PATH),
                new ButtonResponse(function(Player $player): FormResult {
                    $player->sendMessage("You clicked Option 1!");
                    return FormResult::CLOSE;
                })
            ),
            new Button(
                'Option 2',
                null,
                new ButtonResponse(function(Player $player): FormResult {
                    $player->sendMessage("Option 2 selected.");
                    return FormResult::CLOSE;
                })
            ),
        ]);
    }
}

// Instantiation sends the form immediately:
new MyListForm($player, $formData, true);

1.2. Dynamic (Fluent Interface)

  1. Call DynamicLongForm::create($title).

  2. Chain methods:

    • setContent($text)
    • addButton($text, $texturePathOrNull, $callback)
    • sendTo($player)
use imperazim\form\long\DynamicLongForm;

DynamicLongForm::create("Quick Menu")
    ->setContent("What do you want to do?")
    ->addButton(
        "Status",
        'textures/blocks/diamond_block',
        function(Player $player): FormResult {
            $player->sendMessage("Status chosen!");
            return FormResult::CLOSE;
        }
    )
    ->addButton(
        "Settings",
        null,
        function(Player $player): FormResult {
            $player->sendMessage("Opening settings...");
            return FormResult::CLOSE;
        }
    )
    ->sendTo($player);

2. Modal Form

A two-button confirmation dialog (confirm/cancel).

2.1. Class-based

  1. Extend ModalForm.

  2. Override four methods:

    • title(): returns a Title.
    • content(): returns a Content.
    • button1(): typically ModalButton::confirm($text).
    • button2(): typically ModalButton::cancel($text).
  3. Implement onConfirm() to handle the “confirm” action. Optionally override onCancel() for custom “cancel” behavior.

  4. Instantiate with true to send immediately.

use imperazim\form\modal\ModalForm;
use imperazim\form\modal\elements\ModalButton;
use imperazim\form\base\Title;
use imperazim\form\base\Content;

class ConfirmationForm extends ModalForm {
    protected function title(Player $player, FormData $formData): Title {
        return new Title('Confirmation');
    }

    protected function content(Player $player, FormData $formData): Content {
        return new Content('Are you sure you want to delete this item?');
    }

    protected function button1(Player $player, FormData $formData): ModalButton {
        return ModalButton::confirm('Yes');
    }

    protected function button2(Player $player, FormData $formData): ModalButton {
        return ModalButton::cancel('No');
    }

    protected function onConfirm(Player $player, FormData $formData): FormResult {
        $player->sendMessage('Item deleted!');
        return FormResult::CLOSE;
    }

    // Optionally:
    // protected function onCancel(Player $player, FormData $formData): FormResult { ... }
}

// Sends the form automatically:
new ConfirmationForm($player, $formData, true);

2.2. Dynamic (Fluent Interface)

  1. Call DynamicModalForm::create($title).

  2. Chain methods:

    • setContent($text)
    • setButton1($text, $callback)
    • setButton2($text, $callback)
    • sendTo($player)
use imperazim\form\modal\DynamicModalForm;

DynamicModalForm::create("Save Changes")
    ->setContent("Do you want to save your changes?")
    ->setButton1("Save", function(Player $player, ModalResponse $response): FormResult {
        $player->sendMessage('Changes saved!');
        return FormResult::CLOSE;
    })
    ->setButton2("Cancel", function(Player $player, ModalResponse $response): FormResult {
        $player->sendMessage('Operation canceled.');
        return FormResult::CLOSE;
    })
    ->sendTo($player);

3. Custom Form

A flexible form with multiple input elements (text fields, toggles, sliders, dropdowns, etc.).

3.1. Class-based

  1. Extend CustomForm.

  2. Override two methods:

    • title(): returns a Title.
    • elements(): returns an ElementCollection built from individual element objects (Label, Input, Toggle, Slider, Dropdown, StepSlider).
  3. Implement onSubmit() to process submitted values via CustomResponse.

  4. Instantiate with true to send immediately.

use imperazim\form\custom\CustomForm;
use imperazim\form\custom\elements\ElementCollection;
use imperazim\form\custom\elements\Input;
use imperazim\form\custom\elements\Toggle;
use imperazim\form\custom\elements\Slider;
use imperazim\form\custom\elements\Dropdown;
use imperazim\form\custom\elements\Option;
use imperazim\form\custom\response\CustomResponse;
use imperazim\form\base\Title;

class SettingsForm extends CustomForm {
    protected function title(Player $player, FormData $formData): Title {
        return new Title('General Settings');
    }

    protected function elements(Player $player, FormData $formData): ElementCollection {
        return ElementCollection::fromArray([
            new Input('username', 'Username:', 'Type your name', $player->getName()),
            new Toggle('notifications', 'Enable notifications?', true),
            new Slider('volume', 'Sound Volume', 0, 100, 1, 50),
            new Dropdown('language', 'Language', [
                new Option('en', 'English'),
                new Option('es', 'Spanish'),
                new Option('pt', 'Portuguese')
            ], 'en')
        ]);
    }

    protected function onSubmit(Player $player, CustomResponse $response): FormResult {
        $username = $response->getInput('username');
        $volume = $response->getSlider('volume');
        $languageId = $response->getSelectedOption('language')->getId();

        $player->sendMessage("Settings saved: $username, Volume $volume, Language $languageId");
        return FormResult::CLOSE;
    }
}

// Sends the form automatically:
new SettingsForm($player, $formData, true);

3.2. Dynamic (Fluent Interface)

  1. Call DynamicCustomForm::create($title).

  2. Chain methods:

    • addElement($elementObject) for each element.
    • setOnSubmit($callback) to handle submission.
    • sendTo($player) to display.
use imperazim\form\custom\DynamicCustomForm;
use imperazim\form\custom\elements\Input;
use imperazim\form\custom\elements\Toggle;

DynamicCustomForm::create("Player Profile")
    ->addElement(new Input('nickname', 'Nickname:', 'Enter your nickname...', $player->getName()))
    ->addElement(new Toggle('pvp', 'Enable PvP?', false))
    ->setOnSubmit(function(Player $player, CustomResponse $response): FormResult {
        $nick = $response->getInput('nickname');
        $pvpStatus = $response->getToggle('pvp') ? 'enabled' : 'disabled';
        $player->sendMessage("Nickname: $nick | PvP: $pvpStatus");
        return FormResult::CLOSE;
    })
    ->sendTo($player);

CustomForm Elements

Element Description Example Creation
Label Informational, non-interactive text new Label('Welcome!')
Input Text input field new Input('id', 'Label', 'Placeholder', 'Default value')
Toggle On/off switch new Toggle('id', 'Enable feature?', true)
Slider Numeric range selector new Slider('id', 'Volume', 0, 100, 5, 50)
Dropdown Single-select option list new Dropdown('id', 'Choose a color', [new Option('r','Red')], 'r')
StepSlider Visual step selector new StepSlider('id', 'Difficulty', [new Option('easy','Easy')], 'easy')

State Management (FormData)

Use FormData to share data between forms:

use imperazim\form\FormData;

// Create FormData with initial values:
$formData = new FormData([
    'playerName' => $player->getName(),
    'score'      => 1000,
]); // Instantiate FormData and optional, the parameter accepts arrays!

// Retrieve values in any form:
$playerName = $formData->get('playerName'); // string
$score      = $formData->get('score');      // int 
or 
$playerName = $formData['playerName']; // string
$score      = $formData['score'];      // int 

Flow Control (FormResult)

After a form interaction, return one of:

  • FormResult::CLOSE — close the form for the player.
  • FormResult::KEEP — keep the form open (e.g., for validation, re-prompt).
protected function onSubmit(Player $player, CustomResponse $response): FormResult {
    // If "name" is empty, show an error and keep the form open:
    if ($response->getInput('name') === '') {
        $player->sendMessage("The 'name' field cannot be empty!");
        return FormResult::KEEP;
    }

    // Otherwise, close the form:
    return FormResult::CLOSE;
}

Example: Test Command

This example registers a /testform command to open different types of forms:

namespace your\plugin\namespace;

use pocketmine\plugin\PluginBase;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\player\Player;
use imperazim\form\FormData;
use imperazim\form\long\DynamicLongForm;
use imperazim\form\modal\DynamicModalForm;
use imperazim\form\custom\DynamicCustomForm;

class Main extends PluginBase {
    public function onEnable(): void {
        $this->getServer()->getCommandMap()->register('testform', new FormCommand());
    }
}

class FormCommand extends Command {
    public function __construct() {
        parent::__construct("testform", "Test command for forms", "/testform <type>");
    }

    public function execute(CommandSender $sender, string $label, array $args): void {
        if (!$sender instanceof Player) {
            $sender->sendMessage("This command can only be used by a player.");
            return;
        }

        $type = $args[0] ?? '';
        switch (strtolower($type)) {
            case 'long':
                // Class-based ListForm (auto-sent)
                new MyListForm($sender, new FormData(), true);
                break;

            case 'long_dynamic':
                // Dynamic ListForm
                DynamicLongForm::create("Quick Menu")
                    ->setContent("Choose:")
                    ->addButton("Option A", null, fn(Player $p) => FormResult::CLOSE)
                    ->sendTo($sender);
                break;

            case 'custom':
                // Class-based CustomForm (auto-sent)
                new SettingsForm($sender, new FormData(), true);
                break;

            case 'modal_dynamic':
                // Dynamic ModalForm
                DynamicModalForm::create("Confirmation")
                    ->setContent("Do you wish to continue?")
                    ->setButton1("Yes", fn(Player $p, $r) => FormResult::CLOSE)
                    ->setButton2("No", fn(Player $p, $r) => FormResult::CLOSE)
                    ->sendTo($sender);
                break;

            default:
                $sender->sendMessage("Usage: /testform <long|long_dynamic|custom|modal_dynamic>");
        }
    }
}