Гайд mimgui — Dear ImGui for MoonLoader

Добро пожаловать в гайд по mimgui.
mimgui — это новая графическая библиотека, написанная в результате устаревания предыдущей графической библиотеки Moon ImGui, использующей Dear ImGui v.1.52; использующая в своей основе свежий релиз Dear ImGui v.1.72. Новая библиотека включает в себя все основные возможности фреймворка, а API максимально приближен к оригинальному.

Содержание:


GitHub ImGui:
GitHub mimgui:

Скачать mimgui
Установка: переместить папку mimgui из архива в папку «*Корневая папка с игрой*/moonloader/lib»



Основная информация
В mimgui используется относительно последняя версия ImGui (1.72): на момент написания статьи последняя его версия — 1.79.
Изначально написание этой статьи планировалось после выхода предстоящей версии MoonLoader, в которой должен был быть менеджер зависимостей, и сама библиотека должна была поставляться с помощью функционала МЗ, однако её релиз был отложен на неопределенный срок. В качестве основы используется LuaJit ImGui , который, в свою очередь, в качестве основы использует cimgui.

mimgui разрабатывался с декабря 2018 года, однако, широкую популярность он получил только в июле-августе 2019 года, как раз
в период выхода первой beta-версии MoonLoader 027.

Примеры использования mimgui можно увидеть в самом репозитории, но несмотря на это, в этой теме также отдельно будут добавлены примеры использования.




Примеры использования
Давайте напишем примитивный скрипт с использованием mimgui.

Lua:
local imgui = require 'mimgui' -- Подключаем саму библиотеку

local newFrame = imgui.OnFrame( --[[Сама функция создания фрейма, их может быть сколько вашей душе угодно.
                                    Обратите внимание, что в mimgui рекомендуется создавать отдельный
                                    фрейм для каждого окна, однако это не является обязательным.]]
    function() return true end, -- Определяет, выполняется/отображается ли текущий фрейм.
    function(player)            --[[Сама область, в которой уже будем рисовать элементы.
                                    В функцию в качестве первой переменной передаются список функций
                                    для взаимодействия с локальным игроком и рядом нескольких возможностей.]]
        imgui.Begin("Main Window")  -- Создаём новое окно с заголовком 'Main Window'
        imgui.Text("Hello")         -- Добавляем туда текст 'Hello'
        imgui.End()                 -- Объявляем конец данного окна
    end
)

function main()
    wait(-1)
end

Результат:

Screenshot_1.png


Само собой, это не все возможности ImGui, поэтому немного преобразим наш скрипт: добавим размер, позицию по умолчанию и клавишу активации для показа окна.


Lua:
local imgui = require 'mimgui'
local vkeys = require 'vkeys'       --[[Библиотека со списком индексов клавиш и функциями для
                                        взаимодействия с ними.]]

local wm = require 'windows.message'    -- Список событий для окна игры

local new = imgui.new               --[[Создаём короткий псевдоним для функции,
                                        создающего буфера для различных функций ImGui]]
local renderWindow = new.bool(--[[true/false, по умолч. false]])
local sizeX, sizeY = getScreenResolution()

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5)) -- Укажем положение окна по центру и выставим оффсет 0.5, чтобы рендер шёл от середины окна
        imgui.SetNextWindowSize(imgui.ImVec2(200, 150), imgui.Cond.FirstUseEver) -- Укажем размер
        imgui.Begin("Main Window", renderWindow)
        imgui.Text("Hello")
        imgui.Text(string.format("Current render mode: %s", renderWindow[0]))
        imgui.End()
    end
)

function main()
    addEventHandler('onWindowMessage', function(msg, wparam, lparam) -- Сама функция, в которой будем обрабатывать горячие клавиши. Обратите внимание, что данный способ является наиболее верным в плане оптимизации.
        if msg == wm.WM_KEYDOWN or msg == wm.WM_SYSKEYDOWN then -- Если клавиша нажата
            if wparam == vkeys.VK_X then -- И если это клавиша X
                renderWindow[0] = not renderWindow[0] -- Переключаем состояние рендера
            end
        end
    end)
    wait(-1)
end

Результат:
Screenshot_2.png


Но, ведь ничего не изменилось: размер тот же, положение то же самое: в левом верхнем углу, почему?
Дело в том, что mimgui умеет сохранять данные окон по их индексу. Индексы окон — это их заголовки, поэтому заголовки также следует делать уникальными.
Если вам необходимы одинаковые названия окон, то достаточно после названия окна добавить ##уникальное_значение, не беспокойтесь, он не будет виден. Обратите внимание, что это следует делать во всех случаях: InputText(Multiline), InputInt, Button и так далее; абсолютно во всех, иначе работать у вас будет только первая кнопка/инпут.

Хорошо, с индексом разобрались, возможно, вам понадобится убрать автоматическое запоминание, давайте выключим:


Lua:
local imgui = require 'mimgui'
local vkeys = require 'vkeys'

local wm = require 'windows.message'
local new = imgui.new

local renderWindow = new.bool()
local sizeX, sizeY = getScreenResolution()

imgui.OnInitialize(function()   --[[Функция, вызывающаяся один раз за период жизни скрипта.
                                    Обратите внимание, что пока никакое ImGui окно ни разу не показывалось,
                                    функция не вызовется и это может вызвать ошибки об отсутствии
                                    каких-либо переменных, если вы их здесь объявили.
                                    Поэтому, здесь следует просто изменять значения по умолчанию, например:
                                    цвет элементов, "сохранять ли настройки и в какой файл"
                                    Либо подгружать картинки, необходимые для показа окнам ImGui
                                    Если вы за пределами ImGui попытаетесь подгрузить картинку, вы поймаете ошибку.]]

    -- Выключаем сохранение. По умолчанию: moonloader/config/mimgui/%scriptfilename%.ini
    imgui.GetIO().IniFilename = nil
end)

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
        imgui.SetNextWindowSize(imgui.ImVec2(200, 150), imgui.Cond.FirstUseEver)
        imgui.Begin("Main Window", renderWindow)
        imgui.Text("Hello")
        imgui.Text(string.format("Current render mode: %s", renderWindow[0]))
        imgui.End()
    end
)

function main()
    addEventHandler('onWindowMessage', function(msg, wparam, lparam)
        if msg == wm.WM_KEYDOWN or msg == wm.WM_SYSKEYDOWN then
            if wparam == vkeys.VK_X then
                renderWindow[0] = not renderWindow[0]
            end
        end
    end)
    wait(-1)
end

Теперь окно увеличилось, отображается по центру и его можно скрыть:
Screenshot_3.png


Давайте теперь напишем что-то на русском языке:
Lua:
local imgui = require 'mimgui'
local ffi = require 'ffi' -- Подключаем библиотеку ffi для использования возможностей Си (C)
local vkeys = require 'vkeys'

local wm = require 'windows.message'
local new, str, sizeof = imgui.new, ffi.string, ffi.sizeof

local renderWindow = new.bool()
local inputField = new.char[256 --[[Указываем размер]]](--[[Здесь можно указать какой-либо текст]])
local sizeX, sizeY = getScreenResolution()

imgui.OnInitialize(function()
    imgui.GetIO().IniFilename = nil
end)

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
        imgui.SetNextWindowSize(imgui.ImVec2(200, 150), imgui.Cond.FirstUseEver)
        imgui.Begin("Main Window", renderWindow)
        imgui.Text("Hello")
        imgui.Text(string.format("Current render mode: %s", renderWindow[0]))
        if imgui.InputText("Привет", inputField, sizeof(inputField)) then
            -- Первое: уникальное название инпута, второе: само поле, третье: максимальная длина текста/размер инпута.
            print(str(inputField)) -- Читаем значение инпута через функцию str
        end
        if imgui.Button("Очистить поле") then
            imgui.StrCopy(inputField, '') -- Можно вписать какое-либо значение в инпут, при желании.
        end
        imgui.End()
    end
)

function main()
    addEventHandler('onWindowMessage', function(msg, wparam, lparam)
        if msg == wm.WM_KEYDOWN or msg == wm.WM_SYSKEYDOWN then
            if wparam == vkeys.VK_X then
                renderWindow[0] = not renderWindow[0]
            end
        end
    end)
    wait(-1)
end

Результат:
Screenshot_4.png


Мы видим здесь каракули и вопросительные знаки, почему это происходит?

Работа с другими языками на примере русского
В MoonLoader 025 были добавлены библиотеки lua-iconv и encoding, они призваны помочь в работе с разными кодировками текста.
Следующий пример показывает, как использовать текст на русском в ImGui:
Скрипт должен быть сохранён в кодировке Windows-1251 (конкретно для данного примера)
Если в вашем скрипте имеется огромный код с использованием ImGui и мало взаимодействия с функциями MoonLoader'a либо SAMPFUNCS'a, то вы при желании можете сохранить ваш скрипт в UTF-8 и вам не придётся проделывать все эти операции.


Lua:
local imgui = require 'mimgui'
local ffi = require 'ffi'
local vkeys = require 'vkeys'
local encoding = require 'encoding' --[[Подключаем библиотеку для чтения/записи данных с кодировкой,
                                        отличающейся от кодировки нашего скрипта.]]

encoding.default = 'CP1251'         --[[Указываем кодировку по умолчанию. Обратите внимание,
                                        что она должна совпадать с кодировкой вашего скрипта.]]
local u8 = encoding.UTF8            -- И создаём короткий псевдоним для кодировщика UTF-8

local wm = require 'windows.message'
local new, str, sizeof = imgui.new, ffi.string, ffi.sizeof

local renderWindow, freezePlayer, removeCursor = new.bool(), new.bool(), new.bool()
local inputField = new.char[256](--[[Здесь также следует кодировать информацию!]])
local sizeX, sizeY = getScreenResolution()

imgui.OnInitialize(function()
    imgui.GetIO().IniFilename = nil
end)

local newFrame = imgui.OnFrame(
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5))
        imgui.SetNextWindowSize(imgui.ImVec2(220, 200), imgui.Cond.FirstUseEver)
        imgui.Begin("Main Window", renderWindow)
        imgui.Text("Hello")
        imgui.Text(string.format("Current render mode: %s", renderWindow[0]))
        if imgui.InputText(u8"Привет", inputField, sizeof(inputField)) then
            -- Кодируем название инпута
            print(u8:decode(str(inputField))) -- Декодируем в Windows-1251
        end
        if imgui.Button(u8"Очистить поле") then -- Кодируем название кнопки
            imgui.StrCopy(inputField, '')
        end
        if imgui.Checkbox(u8'Заморозить игрока', freezePlayer) then -- Кодируем название кнопки
            player.LockPlayer = freezePlayer[0]
        end
        if imgui.Checkbox(u8'Скрыть курсор', removeCursor) then -- Кодируем название кнопки
            player.HideCursor = removeCursor[0]
        end
        if player.HideCursor then
            imgui.Text(u8'Курсор скрыт') -- Кодируем выводимый текст
        end
        imgui.End()
    end
)

function main()
    addEventHandler('onWindowMessage', function(msg, wparam, lparam)
        if msg == wm.WM_KEYDOWN or msg == wm.WM_SYSKEYDOWN then
            if wparam == vkeys.VK_X then
                renderWindow[0] = not renderWindow[0]
            end
        end
    end)
    wait(-1)
end

Результат:
Screenshot_5.png


В примерах не было затронуто наличие "префрейма" (BeforeFrame), применение его и остальных возможностей вы можете увидеть в репозитории по ссылке:




Главные различия между ImGui C++ API и mimgui Lua API

ОписаниеВ C++ ImGuiВ Lua mimgui
Все функции из пространства имён ImGui, как и все типы, и все перечисления находятся в таблице, возвращаемой модулем​
ImGui::Text("text");
ImVec2(0.1f, 2.3f);
imgui.Text("text")
imgui.ImVec2(0.1, 2.3)
Названия перечислений (enum) и их значений лишились префиксов и символа "_" в концеImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResizeimgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoResize
Значения базовых типов, которые в ImGui записываются по указателю, должны быть использованы через ffistatic bool win = false;
ImGui::Begin("window", &win);
win = false;
local win = imgui.new.bool(false)
imgui.Begin("window", win)
win[0] = false
Использование функций InputText и InputTextMultilinechar buf[256];
ImGui::InputText('input', buf, IM_ARRAYSIZE(buf))
local buf = imgui.new.char[256]()
imgui.InputText('input', buf, ffi.sizeof(buf))
Динамические массивы в виде массива указателей следует объявлять через fficonst char* items[] = {"1", "2", "3"};
ImGui::ListBox("list", &lb_cur, items, 3)
local itemsList = {"1", "2", "3"}
local current = imgui.new.int(0)
local items = imgui.new['const char*'][#itemsList](itemsList)
imgui.ListBoxStr_arr("list", current, items, #itemsList)


Главные различия между MoonImGui и mimgui
Для взаимодействия с ImGui теперь используется встроенная в LuaJIT библиотека ffi, а не самописные функции. Поэтому, получается так, что когда мы пишем код, мы "пишем код" на С++. Поэтому, добавленные в MoonImGui типы: ImBool, ImBuffer, ImInt, ImFloat, ImCallback не требуются, и им на замену пришли встроенные и не встроенные в Си типы:

ТипИспользование в MoonImGuiИспользование в mimgui
Bool​
local bool = imgui.ImBool(true/false)​
local bool = imgui.new.bool(true/false)​
Int​
local int = imgui.ImInt(5)​
local int = imgui.new.int(5)​
Char​
local buffer = imgui.ImBuffer(128, "hello")​
local buffer = imgui.new.char[128]("hello")​
Float​
local float = imgui.ImFloat(5.12)​
local float = imgui.new.float(5.12)​
Callback​
local test = function(data) print("hey") return 0 end
local callback = imgui.ImCallback(test)​
local test = function(data) print("hey") return 0 end
local callback = ffi.cast('int (*)(ImGuiInputTextCallbackData* data)', test)​

Следует отметить, что получение исходных значений так же подверглось изменению. Если раньше исходное значение можно было получить через ключ v (buffer.v; int.v), то в mimgui они получаются с помощью нулевого индекса (int[0]; float[0]; bool[0]), а для типа Char значение необходимо получать через ffi.string (ffi.string(buffer)). Не нужно бояться внесёнными в API изменениям, они очень легко осваиваются и для ежедневного кодинга не нужно вникать в их работу.




Отличительные способности mimgui Lua
В разработке
 
Последнее редактирование:

#Northn

Police Helper «Reborn» — уже ШЕСТЬ лет!
Автор темы
Всефорумный модератор
2,637
2,486
На сколько сложно будет переписать готовый проект на imgui под mimgui, там 5к строк. Много ли придется переписывать?
Нет, не много, должно быть просто
Я уже переписывал, там даже полностью не придётся с нуля писать
 

Tema05

Известный
1,443
404
На сколько сложно будет переписать готовый проект на imgui под mimgui, там 5к строк. Много ли придется переписывать?
Это не сложно но оооочень долго и нудно. Тем более это нельзя автоматизировать
Нет, не много, должно быть просто
Я уже переписывал, там даже полностью не придётся с нуля писать
Я не знаю почему но после создания этой темы у меня началась крашиться GTA из за imgui при разворачивании. До создания темы этого не было. Возникает ощущения что специально сделали в imgui краши чтобы всех заставить переходить на mimgui :)
 
Последнее редактирование:

ArzAh

Потрачен
72
10
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Это не сложно но оооочень долго и нудно. Тем более это нельзя автоматизировать

Я не знаю почему но после создания этой темы у меня началась крашиться GTA из за imgui при разворачивании. До создания темы этого не было. Возникает ощущения что специально сделали в imgui краши чтобы всех заставить переходить на mimgui :)

Это дефолтный краш даже на чистой сборки, если часто сворачивать/разворачивать игру, крашит.
 

Tema05

Известный
1,443
404
Я переписывал 2к, это заеб,лучше пиши на новом имгуи с 0
У меня скрипт состоит из 11к строк, 8к из них ЧИСТОГО imgui + кучу переменных используется вне imgui. Более 1500+ imgui переменных (учитывая повторение). Я целый день как проснулся и до сна монотонно вручную переделывал переменные. За этот полный день я только лишь изменил создание всех переменных, убрал .v и поставил [0] + добавил где нужно ffi.sizeof, ffi.string imgui.StrCopy и очень заебался. Я боюсь представить что если я только переменные столько времени делал сколько займёт всё остальное.
 
  • Вау
Реакции: bottom_text

#Northn

Police Helper «Reborn» — уже ШЕСТЬ лет!
Автор темы
Всефорумный модератор
2,637
2,486
добавил где нужно ffi.sizeof
Lua:
local _InputText = imgui.InputText
function imgui.InputText(name, input, size, flags)
    imgui.PushItemWidth(size or 0)
    local res = _InputText(name, input, ffi.sizeof(input), (flags or 0))
    imgui.PopItemWidth()
    return res
end
 

Tema05

Известный
1,443
404
Lua:
local _InputText = imgui.InputText
function imgui.InputText(name, input, size, flags)
    imgui.PushItemWidth(size or 0)
    local res = _InputText(name, input, ffi.sizeof(input), (flags or 0))
    imgui.PopItemWidth()
    return res
end
Ну так это очевидно, я имею ввиду другие места помимо InputText
Lua:
if #input.v > 4 then
--код
end
шах и мат

Я также использовал поиск и замену по шаблону. Но это уменьшило работу только лишь на 30-40%. Также по-любому будет куча функций которые работают по-другому и нужно опять вникать. + библиотека которые не я писал а в них нужно разобраться. Я не говорю что mimgui это плохо. Просто очень не хочится тратить овер много времени на то что никак не отразится на скрипте.
Lua:
local _InputText = imgui.InputText
function imgui.InputText(name, input, size, flags)
    imgui.PushItemWidth(size or 0)
    local res = _InputText(name, input, ffi.sizeof(input), (flags or 0))
    imgui.PopItemWidth()
    return res
end
Кст я правильно заполнил таблицу? Ты вроде говорил что вне OnFrame что то по другому, но я забыл что именно
Получения значений:BoolIntCharFloatFloat4
Внутри OnFrame[0][0]ffi.string()[0][0], [1], [2], [3]
Вне OnFrame[0][0]ffi.string()[0][0], [1], [2], [3]
 
Последнее редактирование:

lazyman

Новичок
21
1
гайс, я тут решил попробовать сия чудо и внедрить себе в скрипт (простой пдшный), чтобы ознакомиться копировал с хаба код который в примере и заметил, как фпс начал дико просаживаться. это проявляется не сразу, но потом лагает дико, при том, что окно не вызывал даже.
попробовал на разных сборках, ситуация повторилась, а как ток вырезал часть с mimgui, сразу встало все на места.
да, железо не новое, но играть с комфортом можно (периодически).
с чем может быть связано?
 

#Northn

Police Helper «Reborn» — уже ШЕСТЬ лет!
Автор темы
Всефорумный модератор
2,637
2,486
гайс, я тут решил попробовать сия чудо и внедрить себе в скрипт (простой пдшный), чтобы ознакомиться копировал с хаба код который в примере и заметил, как фпс начал дико просаживаться. это проявляется не сразу, но потом лагает дико, при том, что окно не вызывал даже.
попробовал на разных сборках, ситуация повторилась, а как ток вырезал часть с mimgui, сразу встало все на места.
да, железо не новое, но играть с комфортом можно (периодически).
с чем может быть связано?
возможно, загружаешь изображение в цикле, а не единожды
 

Tema05

Известный
1,443
404
возможно, загружаешь изображение в цикле, а не единожды
Что по поводу моей таблицы определения значений? Всё правильно?
Просто точно не помню но ты говорил что вне фрейма по другому что-то.
Получения значений:BoolIntCharFloatFloat4
Внутри OnFrame[0][0]ffi.string()[0][0], [1], [2], [3]
Вне OnFrame[0][0]ffi.string()[0][0], [1], [2], [3]
 
Последнее редактирование:

lazyman

Новичок
21
1
возможно, загружаешь изображение в цикле, а не единожды
с изображением не работаю, вот собственно фрейм. вызывается окно через команду.
Lua:
local newFrame = imgui.OnFrame( -- cам фрейм
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5)) -- Укажем положение окна по центру и выставим оффсет 0.5, чтобы рендер шёл от середины окна
        imgui.SetNextWindowSize(imgui.ImVec2(200, 150), imgui.Cond.FirstUseEver) -- Укажем размер
        if imgui.BeginTabBar('##1') then
            if imgui.BeginTabItem('Behavior') then
                imgui.Text('Frame drawer behavior configuration')
                imgui.Separator()
                local checkbox = new.bool(player.HideCursor)
                if imgui.Checkbox('Hide cursor', checkbox) then
                    player.HideCursor = checkbox[0]
                end
                checkbox[0] = player.LockPlayer
                if imgui.Checkbox('Lock player', checkbox) then
                    player.LockPlayer = checkbox[0]
                end
                if player.HideCursor then
                    imgui.Text('Press CTRL+SHIFT+C to restore cursor')
                end
                imgui.EndTabItem()
            end
            
            if imgui.BeginTabItem('Encoding') then
                imgui.Text(u8'Текст на русском')
                imgui.Separator()
                imgui.InputText('##input', inputField, ffi.sizeof(inputField) - 1)
                imgui.SameLine()
                if imgui.Button(u8'Записать в лог') then
                    print(u8:decode(str(inputField)))
                end
                if imgui.Button(u8'Загрузить текст из файла "moonloader/text.txt"') then
                    local f = io.open('moonloader/text.txt', 'r')
                    if f then
                        local text = f:read('*a')
                        imgui.StrCopy(demo.textBuffer, cyr:decode(text))
                        f:close()
                    end
                end
                imgui.EndTabItem()
            end
        end
        imgui.End()
    end
    
function cmd_es(arg) -- функция (команда), которой вызываю открытие/закрытие окна
    renderWindow[0] = not renderWindow[0]
end
 

#Northn

Police Helper «Reborn» — уже ШЕСТЬ лет!
Автор темы
Всефорумный модератор
2,637
2,486
Что по поводу моей таблицы определения значений? Всё правильно?
Просто точно не помню но ты говорил что вне фрейма по другому что-то.
Получения значений:BoolIntCharFloatFloat4
Внутри OnFrame[0][0]ffi.string()[0][0], [1], [2], [3]
Вне OnFrame[0][0]ffi.string()[0][0], [1], [2], [3]
подгрузка изображений должна быть в BeforeFrame/PreFrame, но в префрейме изображение должно подгрузиться единожды
с изображением не работаю, вот собственно фрейм. вызывается окно через команду.
Lua:
local newFrame = imgui.OnFrame( -- cам фрейм
    function() return renderWindow[0] end,
    function(player)
        imgui.SetNextWindowPos(imgui.ImVec2(sizeX / 2, sizeY / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5)) -- Укажем положение окна по центру и выставим оффсет 0.5, чтобы рендер шёл от середины окна
        imgui.SetNextWindowSize(imgui.ImVec2(200, 150), imgui.Cond.FirstUseEver) -- Укажем размер
        if imgui.BeginTabBar('##1') then
            if imgui.BeginTabItem('Behavior') then
                imgui.Text('Frame drawer behavior configuration')
                imgui.Separator()
                local checkbox = new.bool(player.HideCursor)
                if imgui.Checkbox('Hide cursor', checkbox) then
                    player.HideCursor = checkbox[0]
                end
                checkbox[0] = player.LockPlayer
                if imgui.Checkbox('Lock player', checkbox) then
                    player.LockPlayer = checkbox[0]
                end
                if player.HideCursor then
                    imgui.Text('Press CTRL+SHIFT+C to restore cursor')
                end
                imgui.EndTabItem()
            end
          
            if imgui.BeginTabItem('Encoding') then
                imgui.Text(u8'Текст на русском')
                imgui.Separator()
                imgui.InputText('##input', inputField, ffi.sizeof(inputField) - 1)
                imgui.SameLine()
                if imgui.Button(u8'Записать в лог') then
                    print(u8:decode(str(inputField)))
                end
                if imgui.Button(u8'Загрузить текст из файла "moonloader/text.txt"') then
                    local f = io.open('moonloader/text.txt', 'r')
                    if f then
                        local text = f:read('*a')
                        imgui.StrCopy(demo.textBuffer, cyr:decode(text))
                        f:close()
                    end
                end
                imgui.EndTabItem()
            end
        end
        imgui.End()
    end
  
function cmd_es(arg) -- функция (команда), которой вызываю открытие/закрытие окна
    renderWindow[0] = not renderWindow[0]
end
всё нормально с кодом, не знаю что у тебя не так
 

VolodyaHoi

Участник
53
44
Как изменить стиль имгуи? И как можно реализовать переключение между кнопками через клавиатуру,а не мышкой