frontend-tools: Add scripting tool
Adds a scripting tool that gives the users the ability to load scripts and change their settings.
This commit is contained in:
parent
9eabfdbf1e
commit
0b01e4c7a1
@ -11,6 +11,8 @@ if(UNIX AND NOT APPLE)
|
|||||||
include_directories(${X11_INCLUDE_DIR})
|
include_directories(${X11_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/deps/obs-scripting")
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/frontend-tools-config.h.in"
|
"${CMAKE_CURRENT_SOURCE_DIR}/frontend-tools-config.h.in"
|
||||||
"${CMAKE_BINARY_DIR}/config/frontend-tools-config.h")
|
"${CMAKE_BINARY_DIR}/config/frontend-tools-config.h")
|
||||||
@ -21,12 +23,19 @@ set(frontend-tools_HEADERS
|
|||||||
auto-scene-switcher.hpp
|
auto-scene-switcher.hpp
|
||||||
output-timer.hpp
|
output-timer.hpp
|
||||||
tool-helpers.hpp
|
tool-helpers.hpp
|
||||||
|
../../properties-view.hpp
|
||||||
|
../../properties-view.moc.hpp
|
||||||
|
../../vertical-scroll-area.hpp
|
||||||
|
../../double-slider.hpp
|
||||||
)
|
)
|
||||||
set(frontend-tools_SOURCES
|
set(frontend-tools_SOURCES
|
||||||
${frontend-tools_SOURCES}
|
${frontend-tools_SOURCES}
|
||||||
auto-scene-switcher.cpp
|
auto-scene-switcher.cpp
|
||||||
frontend-tools.c
|
frontend-tools.c
|
||||||
output-timer.cpp
|
output-timer.cpp
|
||||||
|
../../properties-view.cpp
|
||||||
|
../../vertical-scroll-area.cpp
|
||||||
|
../../double-slider.cpp
|
||||||
)
|
)
|
||||||
set(frontend-tools_UI
|
set(frontend-tools_UI
|
||||||
${frontend-tools_UI}
|
${frontend-tools_UI}
|
||||||
@ -34,6 +43,25 @@ set(frontend-tools_UI
|
|||||||
forms/output-timer.ui
|
forms/output-timer.ui
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(ENABLE_SCRIPTING)
|
||||||
|
set(frontend-tools_HEADERS
|
||||||
|
${frontend-tools_HEADERS}
|
||||||
|
scripts.hpp
|
||||||
|
)
|
||||||
|
set(frontend-tools_SOURCES
|
||||||
|
${frontend-tools_SOURCES}
|
||||||
|
scripts.cpp
|
||||||
|
)
|
||||||
|
set(frontend-tools_UI
|
||||||
|
${frontend-tools_UI}
|
||||||
|
forms/scripts.ui
|
||||||
|
)
|
||||||
|
set(EXTRA_LIBS
|
||||||
|
${EXTRA_LIBS}
|
||||||
|
obs-scripting
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(frontend-tools_PLATFORM_SOURCES
|
set(frontend-tools_PLATFORM_SOURCES
|
||||||
auto-scene-switcher-win.cpp)
|
auto-scene-switcher-win.cpp)
|
||||||
@ -79,6 +107,7 @@ add_library(frontend-tools MODULE
|
|||||||
)
|
)
|
||||||
target_link_libraries(frontend-tools
|
target_link_libraries(frontend-tools
|
||||||
${frontend-tools_PLATFORM_LIBS}
|
${frontend-tools_PLATFORM_LIBS}
|
||||||
|
${EXTRA_LIBS}
|
||||||
obs-frontend-api
|
obs-frontend-api
|
||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
libobs)
|
libobs)
|
||||||
|
@ -24,3 +24,22 @@ OutputTimer.Stream.StoppingIn="Streaming stopping in:"
|
|||||||
OutputTimer.Record.StoppingIn="Recording stopping in:"
|
OutputTimer.Record.StoppingIn="Recording stopping in:"
|
||||||
OutputTimer.Stream.EnableEverytime="Enable streaming timer every time"
|
OutputTimer.Stream.EnableEverytime="Enable streaming timer every time"
|
||||||
OutputTimer.Record.EnableEverytime="Enable recording timer every time"
|
OutputTimer.Record.EnableEverytime="Enable recording timer every time"
|
||||||
|
|
||||||
|
Scripts="Scripts"
|
||||||
|
LoadedScripts="Loaded Scripts"
|
||||||
|
AddScripts="Add Scripts"
|
||||||
|
RemoveScripts="Remove Scripts"
|
||||||
|
ReloadScripts="Reload Scripts"
|
||||||
|
LoadedScripts="Loaded Scripts"
|
||||||
|
LuaSettings="Lua Settings"
|
||||||
|
LuaSettings.LuaDepPaths="Lua Dependency Paths"
|
||||||
|
LuaSettings.AddLuaDepPath="Add Lua Dependency Path"
|
||||||
|
LuaSettings.RemoveLuaDepPath="Remove Lua Dependency Path"
|
||||||
|
PythonSettings="Python Settings"
|
||||||
|
PythonSettings.PythonInstallPath32bit="Python Install Path (32bit)"
|
||||||
|
PythonSettings.PythonInstallPath64bit="Python Install Path (64bit)"
|
||||||
|
PythonSettings.BrowsePythonPath="Browse Python Path"
|
||||||
|
ScriptLogWindow="Script Log"
|
||||||
|
|
||||||
|
FileFilter.ScriptFiles="Script Files"
|
||||||
|
FileFilter.AllFiles="All Files"
|
||||||
|
180
UI/frontend-plugins/frontend-tools/data/scripts/countdown.lua
Normal file
180
UI/frontend-plugins/frontend-tools/data/scripts/countdown.lua
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
obs = obslua
|
||||||
|
source_name = ""
|
||||||
|
total_seconds = 0
|
||||||
|
|
||||||
|
cur_seconds = 0
|
||||||
|
last_text = ""
|
||||||
|
stop_text = ""
|
||||||
|
activated = false
|
||||||
|
|
||||||
|
hotkey_id = obs.OBS_INVALID_HOTKEY_ID
|
||||||
|
|
||||||
|
-- Function to set the time text
|
||||||
|
function set_time_text()
|
||||||
|
local seconds = math.floor(cur_seconds % 60)
|
||||||
|
local total_minutes = math.floor(cur_seconds / 60)
|
||||||
|
local minutes = math.floor(total_minutes % 60)
|
||||||
|
local hours = math.floor(total_minutes / 60)
|
||||||
|
local text = string.format("%02d:%02d:%02d", hours, minutes, seconds)
|
||||||
|
|
||||||
|
if cur_seconds < 1 then
|
||||||
|
text = stop_text
|
||||||
|
end
|
||||||
|
|
||||||
|
if text ~= last_text then
|
||||||
|
local source = obs.obs_get_source_by_name(source_name)
|
||||||
|
if source ~= nil then
|
||||||
|
local settings = obs.obs_data_create()
|
||||||
|
obs.obs_data_set_string(settings, "text", text)
|
||||||
|
obs.obs_source_update(source, settings)
|
||||||
|
obs.obs_data_release(settings)
|
||||||
|
obs.obs_source_release(source)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
last_text = text
|
||||||
|
end
|
||||||
|
|
||||||
|
function timer_callback()
|
||||||
|
cur_seconds = cur_seconds - 1
|
||||||
|
if cur_seconds < 0 then
|
||||||
|
obs.remove_current_callback()
|
||||||
|
cur_seconds = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
set_time_text()
|
||||||
|
end
|
||||||
|
|
||||||
|
function activate(activating)
|
||||||
|
if activated == activating then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
activated = activating
|
||||||
|
|
||||||
|
if activating then
|
||||||
|
cur_seconds = total_seconds
|
||||||
|
set_time_text()
|
||||||
|
obs.timer_add(timer_callback, 1000)
|
||||||
|
else
|
||||||
|
obs.timer_remove(timer_callback)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Called when a source is activated/deactivated
|
||||||
|
function activate_signal(cd, activating)
|
||||||
|
local source = obs.calldata_source(cd, "source")
|
||||||
|
if source ~= nil then
|
||||||
|
local name = obs.obs_source_get_name(source)
|
||||||
|
if (name == source_name) then
|
||||||
|
activate(activating)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function source_activated(cd)
|
||||||
|
activate_signal(cd, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
function source_deactivated(cd)
|
||||||
|
activate_signal(cd, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function reset(pressed)
|
||||||
|
if not pressed then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
activate(false)
|
||||||
|
local source = obs.obs_get_source_by_name(source_name)
|
||||||
|
if source ~= nil then
|
||||||
|
local active = obs.obs_source_active(source)
|
||||||
|
obs.obs_source_release(source)
|
||||||
|
activate(active)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function reset_button_clicked(props, p)
|
||||||
|
reset(true)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
-- A function named script_properties defines the properties that the user
|
||||||
|
-- can change for the entire script module itself
|
||||||
|
function script_properties()
|
||||||
|
local props = obs.obs_properties_create()
|
||||||
|
obs.obs_properties_add_int(props, "duration", "Duration (minutes)", 1, 100000, 1)
|
||||||
|
|
||||||
|
local p = obs.obs_properties_add_list(props, "source", "Text Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
|
||||||
|
local sources = obs.obs_enum_sources()
|
||||||
|
if sources ~= nil then
|
||||||
|
for _, source in ipairs(sources) do
|
||||||
|
source_id = obs.obs_source_get_id(source)
|
||||||
|
if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
|
||||||
|
local name = obs.obs_source_get_name(source)
|
||||||
|
obs.obs_property_list_add_string(p, name, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
obs.source_list_release(sources)
|
||||||
|
|
||||||
|
obs.obs_properties_add_text(props, "stop_text", "Final Text", obs.OBS_TEXT_DEFAULT)
|
||||||
|
obs.obs_properties_add_button(props, "reset_button", "Reset Timer", reset_button_clicked)
|
||||||
|
|
||||||
|
return props
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A function named script_description returns the description shown to
|
||||||
|
-- the user
|
||||||
|
function script_description()
|
||||||
|
return "Sets a text source to act as a countdown timer when the source is active.\n\nMade by Jim"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A function named script_update will be called when settings are changed
|
||||||
|
function script_update(settings)
|
||||||
|
activate(false)
|
||||||
|
|
||||||
|
total_seconds = obs.obs_data_get_int(settings, "duration") * 60
|
||||||
|
source_name = obs.obs_data_get_string(settings, "source")
|
||||||
|
stop_text = obs.obs_data_get_string(settings, "stop_text")
|
||||||
|
|
||||||
|
reset(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A function named script_defaults will be called to set the default settings
|
||||||
|
function script_defaults(settings)
|
||||||
|
obs.obs_data_set_default_int(settings, "duration", 5)
|
||||||
|
obs.obs_data_set_default_string(settings, "stop_text", "Starting soon (tm)")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A function named script_save will be called when the script is saved
|
||||||
|
--
|
||||||
|
-- NOTE: This function is usually used for saving extra data (such as in this
|
||||||
|
-- case, a hotkey's save data). Settings set via the properties are saved
|
||||||
|
-- automatically.
|
||||||
|
function script_save(settings)
|
||||||
|
local hotkey_save_array = obs.obs_hotkey_save(hotkey_id)
|
||||||
|
obs.obs_data_set_array(settings, "reset_hotkey", hotkey_save_array)
|
||||||
|
obs.obs_data_array_release(hotkey_save_array)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- a function named script_load will be called on startup
|
||||||
|
function script_load(settings)
|
||||||
|
-- Connect hotkey and activation/deactivation signal callbacks
|
||||||
|
--
|
||||||
|
-- NOTE: These particular script callbacks do not necessarily have to
|
||||||
|
-- be disconnected, as callbacks will automatically destroy themselves
|
||||||
|
-- if the script is unloaded. So there's no real need to manually
|
||||||
|
-- disconnect callbacks that are intended to last until the script is
|
||||||
|
-- unloaded.
|
||||||
|
local sh = obs.obs_get_signal_handler()
|
||||||
|
obs.signal_handler_connect(sh, "source_activate", source_activated)
|
||||||
|
obs.signal_handler_connect(sh, "source_deactivate", source_deactivated)
|
||||||
|
|
||||||
|
hotkey_id = obs.obs_hotkey_register_frontend("reset_timer_thingy", "Reset Timer", reset)
|
||||||
|
local hotkey_save_array = obs.obs_data_get_array(settings, "reset_hotkey")
|
||||||
|
obs.obs_hotkey_load(hotkey_id, hotkey_save_array)
|
||||||
|
obs.obs_data_array_release(hotkey_save_array)
|
||||||
|
end
|
266
UI/frontend-plugins/frontend-tools/forms/scripts.ui
Normal file
266
UI/frontend-plugins/frontend-tools/forms/scripts.ui
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ScriptsTool</class>
|
||||||
|
<widget class="QWidget" name="ScriptsTool">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>775</width>
|
||||||
|
<height>492</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Scripts</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scriptsTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Scripts</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>LoadedScripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>scripts</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="scripts">
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addScripts">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>AddScripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="accessibleName">
|
||||||
|
<string>AddScripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">addIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="removeScripts">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>RemoveScripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="accessibleName">
|
||||||
|
<string>RemoveScripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">removeIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="reloadScripts">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>ReloadScripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="accessibleName">
|
||||||
|
<string>ReloadScripts</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="flat">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="themeID" stdset="0">
|
||||||
|
<string notr="true">refreshIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="scriptLog">
|
||||||
|
<property name="text">
|
||||||
|
<string>ScriptLogWindow</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="propertiesLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Description</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="description">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="pythonSettingsTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>PythonSettings</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="pythonPathLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>pythonPath</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="pythonPath">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pythonPathBrowse">
|
||||||
|
<property name="accessibleName">
|
||||||
|
<string>PythonSettings.BrowsePythonPath</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Browse</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>510</width>
|
||||||
|
<height>306</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="close">
|
||||||
|
<property name="text">
|
||||||
|
<string>Close</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>tabWidget</tabstop>
|
||||||
|
<tabstop>close</tabstop>
|
||||||
|
<tabstop>pythonPath</tabstop>
|
||||||
|
<tabstop>pythonPathBrowse</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -1,3 +1,22 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ON
|
||||||
|
#define ON 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OFF
|
||||||
|
#define OFF 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define BUILD_CAPTIONS @BUILD_CAPTIONS@
|
#define BUILD_CAPTIONS @BUILD_CAPTIONS@
|
||||||
|
#define ENABLE_SCRIPTING @ENABLE_SCRIPTING@
|
||||||
|
#define COMPILE_LUA @COMPILE_LUA@
|
||||||
|
#define COMPILE_PYTHON @COMPILE_PYTHON@
|
||||||
|
@ -15,6 +15,11 @@ void FreeCaptions();
|
|||||||
void InitOutputTimer();
|
void InitOutputTimer();
|
||||||
void FreeOutputTimer();
|
void FreeOutputTimer();
|
||||||
|
|
||||||
|
#if ENABLE_SCRIPTING
|
||||||
|
void InitScripts();
|
||||||
|
void FreeScripts();
|
||||||
|
#endif
|
||||||
|
|
||||||
bool obs_module_load(void)
|
bool obs_module_load(void)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) && BUILD_CAPTIONS
|
#if defined(_WIN32) && BUILD_CAPTIONS
|
||||||
@ -22,6 +27,9 @@ bool obs_module_load(void)
|
|||||||
#endif
|
#endif
|
||||||
InitSceneSwitcher();
|
InitSceneSwitcher();
|
||||||
InitOutputTimer();
|
InitOutputTimer();
|
||||||
|
#if ENABLE_SCRIPTING
|
||||||
|
InitScripts();
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,4 +40,7 @@ void obs_module_unload(void)
|
|||||||
#endif
|
#endif
|
||||||
FreeSceneSwitcher();
|
FreeSceneSwitcher();
|
||||||
FreeOutputTimer();
|
FreeOutputTimer();
|
||||||
|
#if ENABLE_SCRIPTING
|
||||||
|
FreeScripts();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
519
UI/frontend-plugins/frontend-tools/scripts.cpp
Normal file
519
UI/frontend-plugins/frontend-tools/scripts.cpp
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
#include "scripts.hpp"
|
||||||
|
#include "frontend-tools-config.h"
|
||||||
|
#include "../../properties-view.hpp"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QFontDatabase>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
|
||||||
|
#include <obs.hpp>
|
||||||
|
#include <obs-module.h>
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
#include <obs-scripting.h>
|
||||||
|
|
||||||
|
#include <util/config-file.h>
|
||||||
|
#include <util/platform.h>
|
||||||
|
#include <util/util.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "ui_scripts.h"
|
||||||
|
|
||||||
|
#if COMPILE_PYTHON && (defined(_WIN32) || defined(__APPLE__))
|
||||||
|
#define PYTHON_UI 1
|
||||||
|
#else
|
||||||
|
#define PYTHON_UI 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ARCH_BITS == 64
|
||||||
|
#define ARCH_NAME "64bit"
|
||||||
|
#else
|
||||||
|
#define ARCH_NAME "32bit"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PYTHONPATH_LABEL_TEXT "PythonSettings.PythonInstallPath" ARCH_NAME
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------- */
|
||||||
|
|
||||||
|
using OBSScript = OBSObj<obs_script_t*, obs_script_destroy>;
|
||||||
|
|
||||||
|
struct ScriptData {
|
||||||
|
std::vector<OBSScript> scripts;
|
||||||
|
|
||||||
|
inline obs_script_t *FindScript(const char *path)
|
||||||
|
{
|
||||||
|
for (OBSScript &script : scripts) {
|
||||||
|
const char *script_path = obs_script_get_path(script);
|
||||||
|
if (strcmp(script_path, path) == 0) {
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptOpened(const char *path)
|
||||||
|
{
|
||||||
|
for (OBSScript &script : scripts) {
|
||||||
|
const char *script_path = obs_script_get_path(script);
|
||||||
|
if (strcmp(script_path, path) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static ScriptData *scriptData = nullptr;
|
||||||
|
static ScriptsTool *scriptsWindow = nullptr;
|
||||||
|
static ScriptLogWindow *scriptLogWindow = nullptr;
|
||||||
|
static QPlainTextEdit *scriptLogWidget = nullptr;
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------- */
|
||||||
|
|
||||||
|
ScriptLogWindow::ScriptLogWindow() : QWidget(nullptr)
|
||||||
|
{
|
||||||
|
const QFont fixedFont =
|
||||||
|
QFontDatabase::systemFont(QFontDatabase::FixedFont);
|
||||||
|
|
||||||
|
QPlainTextEdit *edit = new QPlainTextEdit();
|
||||||
|
edit->setReadOnly(true);
|
||||||
|
edit->setFont(fixedFont);
|
||||||
|
edit->setWordWrapMode(QTextOption::NoWrap);
|
||||||
|
|
||||||
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(
|
||||||
|
QDialogButtonBox::Close);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &QWidget::hide);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout();
|
||||||
|
layout->addWidget(edit);
|
||||||
|
layout->addWidget(buttonBox);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
scriptLogWidget = edit;
|
||||||
|
|
||||||
|
resize(600, 400);
|
||||||
|
|
||||||
|
config_t *global_config = obs_frontend_get_global_config();
|
||||||
|
const char *geom = config_get_string(global_config,
|
||||||
|
"ScriptLogWindow", "geometry");
|
||||||
|
if (geom != nullptr) {
|
||||||
|
QByteArray ba = QByteArray::fromBase64(QByteArray(geom));
|
||||||
|
restoreGeometry(ba);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWindowTitle(obs_module_text("ScriptLogWindow"));
|
||||||
|
|
||||||
|
connect(edit->verticalScrollBar(), &QAbstractSlider::sliderMoved,
|
||||||
|
this, &ScriptLogWindow::ScrollChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptLogWindow::~ScriptLogWindow()
|
||||||
|
{
|
||||||
|
config_t *global_config = obs_frontend_get_global_config();
|
||||||
|
config_set_string(global_config,
|
||||||
|
"ScriptLogWindow", "geometry",
|
||||||
|
saveGeometry().toBase64().constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptLogWindow::ScrollChanged(int val)
|
||||||
|
{
|
||||||
|
QScrollBar *scroll = scriptLogWidget->verticalScrollBar();
|
||||||
|
bottomScrolled = (val == scroll->maximum());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptLogWindow::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
|
||||||
|
if (bottomScrolled) {
|
||||||
|
QScrollBar *scroll = scriptLogWidget->verticalScrollBar();
|
||||||
|
scroll->setValue(scroll->maximum());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptLogWindow::AddLogMsg(int log_level, QString msg)
|
||||||
|
{
|
||||||
|
QScrollBar *scroll = scriptLogWidget->verticalScrollBar();
|
||||||
|
bottomScrolled = scroll->value() == scroll->maximum();
|
||||||
|
|
||||||
|
lines += QStringLiteral("\n");
|
||||||
|
lines += msg;
|
||||||
|
scriptLogWidget->setPlainText(lines);
|
||||||
|
|
||||||
|
if (bottomScrolled)
|
||||||
|
scroll->setValue(scroll->maximum());
|
||||||
|
|
||||||
|
if (log_level <= LOG_WARNING) {
|
||||||
|
show();
|
||||||
|
raise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptLogWindow::Clear()
|
||||||
|
{
|
||||||
|
lines.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------- */
|
||||||
|
|
||||||
|
ScriptsTool::ScriptsTool()
|
||||||
|
: QWidget (nullptr),
|
||||||
|
ui (new Ui_ScriptsTool)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
RefreshLists();
|
||||||
|
|
||||||
|
#if PYTHON_UI
|
||||||
|
config_t *config = obs_frontend_get_global_config();
|
||||||
|
const char *path = config_get_string(config, "Python",
|
||||||
|
"Path" ARCH_NAME);
|
||||||
|
ui->pythonPath->setText(path);
|
||||||
|
ui->pythonPathLabel->setText(obs_module_text(PYTHONPATH_LABEL_TEXT));
|
||||||
|
#else
|
||||||
|
delete ui->pythonSettingsTab;
|
||||||
|
ui->pythonSettingsTab = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
delete propertiesView;
|
||||||
|
propertiesView = new QWidget();
|
||||||
|
propertiesView->setSizePolicy(QSizePolicy::Expanding,
|
||||||
|
QSizePolicy::Expanding);
|
||||||
|
ui->propertiesLayout->addWidget(propertiesView);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptsTool::~ScriptsTool()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::RemoveScript(const char *path)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < scriptData->scripts.size(); i++) {
|
||||||
|
OBSScript &script = scriptData->scripts[i];
|
||||||
|
|
||||||
|
const char *script_path = obs_script_get_path(script);
|
||||||
|
if (strcmp(script_path, path) == 0) {
|
||||||
|
scriptData->scripts.erase(
|
||||||
|
scriptData->scripts.begin() + i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::ReloadScript(const char *path)
|
||||||
|
{
|
||||||
|
for (OBSScript &script : scriptData->scripts) {
|
||||||
|
const char *script_path = obs_script_get_path(script);
|
||||||
|
if (strcmp(script_path, path) == 0) {
|
||||||
|
obs_script_reload(script);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::RefreshLists()
|
||||||
|
{
|
||||||
|
ui->scripts->clear();
|
||||||
|
|
||||||
|
for (OBSScript &script : scriptData->scripts) {
|
||||||
|
const char *script_path = obs_script_get_path(script);
|
||||||
|
ui->scripts->addItem(script_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::on_close_clicked()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::on_addScripts_clicked()
|
||||||
|
{
|
||||||
|
const char **formats = obs_scripting_supported_formats();
|
||||||
|
const char **cur_format = formats;
|
||||||
|
QString extensions;
|
||||||
|
QString filter;
|
||||||
|
|
||||||
|
while (*cur_format) {
|
||||||
|
if (!extensions.isEmpty())
|
||||||
|
extensions += QStringLiteral(" ");
|
||||||
|
|
||||||
|
extensions += QStringLiteral("*.");
|
||||||
|
extensions += *cur_format;
|
||||||
|
|
||||||
|
cur_format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extensions.isEmpty()) {
|
||||||
|
filter += obs_module_text("FileFilter.ScriptFiles");
|
||||||
|
filter += QStringLiteral(" (");
|
||||||
|
filter += extensions;
|
||||||
|
filter += QStringLiteral(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
static std::string lastBrowsedDir;
|
||||||
|
|
||||||
|
if (lastBrowsedDir.empty()) {
|
||||||
|
BPtr<char> baseScriptPath = obs_module_file("scripts");
|
||||||
|
lastBrowsedDir = baseScriptPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileDialog dlg(this, obs_module_text("AddScripts"));
|
||||||
|
dlg.setFileMode(QFileDialog::ExistingFiles);
|
||||||
|
dlg.setDirectory(QDir(lastBrowsedDir.c_str()));
|
||||||
|
dlg.setNameFilter(filter);
|
||||||
|
dlg.exec();
|
||||||
|
|
||||||
|
QStringList files = dlg.selectedFiles();
|
||||||
|
if (!files.count())
|
||||||
|
return;
|
||||||
|
|
||||||
|
lastBrowsedDir = dlg.directory().path().toUtf8().constData();
|
||||||
|
|
||||||
|
for (const QString &file : files) {
|
||||||
|
QByteArray pathBytes = file.toUtf8();
|
||||||
|
const char *path = pathBytes.constData();
|
||||||
|
|
||||||
|
if (scriptData->ScriptOpened(path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_script_t *script = obs_script_create(path, NULL);
|
||||||
|
if (script) {
|
||||||
|
scriptData->scripts.emplace_back(script);
|
||||||
|
ui->scripts->addItem(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::on_removeScripts_clicked()
|
||||||
|
{
|
||||||
|
QList<QListWidgetItem *> items = ui->scripts->selectedItems();
|
||||||
|
|
||||||
|
for (QListWidgetItem *item : items)
|
||||||
|
RemoveScript(item->text().toUtf8().constData());
|
||||||
|
RefreshLists();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::on_reloadScripts_clicked()
|
||||||
|
{
|
||||||
|
QList<QListWidgetItem *> items = ui->scripts->selectedItems();
|
||||||
|
for (QListWidgetItem *item : items)
|
||||||
|
ReloadScript(item->text().toUtf8().constData());
|
||||||
|
|
||||||
|
on_scripts_currentRowChanged(ui->scripts->currentRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::on_scriptLog_clicked()
|
||||||
|
{
|
||||||
|
scriptLogWindow->show();
|
||||||
|
scriptLogWindow->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::on_pythonPathBrowse_clicked()
|
||||||
|
{
|
||||||
|
QString curPath = ui->pythonPath->text();
|
||||||
|
QString newPath = QFileDialog::getExistingDirectory(
|
||||||
|
this,
|
||||||
|
ui->pythonPathLabel->text(),
|
||||||
|
curPath);
|
||||||
|
|
||||||
|
if (newPath.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QByteArray array = newPath.toUtf8();
|
||||||
|
const char *path = array.constData();
|
||||||
|
|
||||||
|
config_t *config = obs_frontend_get_global_config();
|
||||||
|
config_set_string(config, "Python", "Path" ARCH_NAME, path);
|
||||||
|
|
||||||
|
ui->pythonPath->setText(newPath);
|
||||||
|
|
||||||
|
if (obs_scripting_python_loaded())
|
||||||
|
return;
|
||||||
|
if (!obs_scripting_load_python(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (OBSScript &script : scriptData->scripts) {
|
||||||
|
enum obs_script_lang lang = obs_script_get_lang(script);
|
||||||
|
if (lang == OBS_SCRIPT_LANG_PYTHON) {
|
||||||
|
obs_script_reload(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on_scripts_currentRowChanged(ui->scripts->currentRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptsTool::on_scripts_currentRowChanged(int row)
|
||||||
|
{
|
||||||
|
ui->propertiesLayout->removeWidget(propertiesView);
|
||||||
|
delete propertiesView;
|
||||||
|
|
||||||
|
if (row == -1) {
|
||||||
|
propertiesView = new QWidget();
|
||||||
|
propertiesView->setSizePolicy(QSizePolicy::Expanding,
|
||||||
|
QSizePolicy::Expanding);
|
||||||
|
ui->propertiesLayout->addWidget(propertiesView);
|
||||||
|
ui->description->setText(QString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray array = ui->scripts->item(row)->text().toUtf8();
|
||||||
|
const char *path = array.constData();
|
||||||
|
|
||||||
|
obs_script_t *script = scriptData->FindScript(path);
|
||||||
|
if (!script) {
|
||||||
|
propertiesView = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSData settings = obs_script_get_settings(script);
|
||||||
|
obs_data_release(settings);
|
||||||
|
|
||||||
|
propertiesView = new OBSPropertiesView(settings, script,
|
||||||
|
(PropertiesReloadCallback)obs_script_get_properties,
|
||||||
|
(PropertiesUpdateCallback)obs_script_update);
|
||||||
|
ui->propertiesLayout->addWidget(propertiesView);
|
||||||
|
ui->description->setText(obs_script_get_description(script));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------- */
|
||||||
|
|
||||||
|
extern "C" void FreeScripts()
|
||||||
|
{
|
||||||
|
obs_scripting_unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void obs_event(enum obs_frontend_event event, void *)
|
||||||
|
{
|
||||||
|
if (event == OBS_FRONTEND_EVENT_EXIT) {
|
||||||
|
delete scriptData;
|
||||||
|
delete scriptsWindow;
|
||||||
|
delete scriptLogWindow;
|
||||||
|
|
||||||
|
} else if (event == OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP) {
|
||||||
|
scriptLogWindow->hide();
|
||||||
|
scriptLogWindow->Clear();
|
||||||
|
|
||||||
|
delete scriptData;
|
||||||
|
scriptData = new ScriptData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_script_data(obs_data_t *load_data, bool, void *)
|
||||||
|
{
|
||||||
|
obs_data_array_t *array = obs_data_get_array(load_data,
|
||||||
|
"scripts-tool");
|
||||||
|
|
||||||
|
delete scriptData;
|
||||||
|
scriptData = new ScriptData;
|
||||||
|
|
||||||
|
size_t size = obs_data_array_count(array);
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
obs_data_t *obj = obs_data_array_item(array, i);
|
||||||
|
const char *path = obs_data_get_string(obj, "path");
|
||||||
|
obs_data_t *settings = obs_data_get_obj(obj, "settings");
|
||||||
|
|
||||||
|
obs_script_t *script = obs_script_create(path, settings);
|
||||||
|
if (script) {
|
||||||
|
scriptData->scripts.emplace_back(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_release(settings);
|
||||||
|
obs_data_release(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scriptsWindow)
|
||||||
|
scriptsWindow->RefreshLists();
|
||||||
|
|
||||||
|
obs_data_array_release(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_script_data(obs_data_t *save_data, bool saving, void *)
|
||||||
|
{
|
||||||
|
if (!saving)
|
||||||
|
return;
|
||||||
|
|
||||||
|
obs_data_array_t *array = obs_data_array_create();
|
||||||
|
|
||||||
|
for (OBSScript &script : scriptData->scripts) {
|
||||||
|
const char *script_path = obs_script_get_path(script);
|
||||||
|
obs_data_t *settings = obs_script_save(script);
|
||||||
|
|
||||||
|
obs_data_t *obj = obs_data_create();
|
||||||
|
obs_data_set_string(obj, "path", script_path);
|
||||||
|
obs_data_set_obj(obj, "settings", settings);
|
||||||
|
obs_data_array_push_back(array, obj);
|
||||||
|
obs_data_release(obj);
|
||||||
|
|
||||||
|
obs_data_release(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_set_array(save_data, "scripts-tool", array);
|
||||||
|
obs_data_array_release(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void script_log(void *, obs_script_t *script, int log_level,
|
||||||
|
const char *message)
|
||||||
|
{
|
||||||
|
QString qmsg;
|
||||||
|
qmsg = QStringLiteral("[%1] %2").arg(
|
||||||
|
obs_script_get_file(script),
|
||||||
|
message);
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(scriptLogWindow, "AddLogMsg",
|
||||||
|
Q_ARG(int, log_level),
|
||||||
|
Q_ARG(QString, qmsg));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void InitScripts()
|
||||||
|
{
|
||||||
|
scriptLogWindow = new ScriptLogWindow();
|
||||||
|
|
||||||
|
obs_scripting_load();
|
||||||
|
obs_scripting_set_log_callback(script_log, nullptr);
|
||||||
|
|
||||||
|
QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction(
|
||||||
|
obs_module_text("Scripts"));
|
||||||
|
|
||||||
|
#if PYTHON_UI
|
||||||
|
config_t *config = obs_frontend_get_global_config();
|
||||||
|
const char *python_path = config_get_string(config, "Python",
|
||||||
|
"Path" ARCH_NAME);
|
||||||
|
|
||||||
|
if (!obs_scripting_python_loaded() && python_path && *python_path)
|
||||||
|
obs_scripting_load_python(python_path);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
scriptData = new ScriptData;
|
||||||
|
|
||||||
|
auto cb = [] ()
|
||||||
|
{
|
||||||
|
obs_frontend_push_ui_translation(obs_module_get_string);
|
||||||
|
|
||||||
|
if (!scriptsWindow) {
|
||||||
|
scriptsWindow = new ScriptsTool();
|
||||||
|
scriptsWindow->show();
|
||||||
|
} else {
|
||||||
|
scriptsWindow->show();
|
||||||
|
scriptsWindow->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_frontend_pop_ui_translation();
|
||||||
|
};
|
||||||
|
|
||||||
|
obs_frontend_add_save_callback(save_script_data, nullptr);
|
||||||
|
obs_frontend_add_preload_callback(load_script_data, nullptr);
|
||||||
|
obs_frontend_add_event_callback(obs_event, nullptr);
|
||||||
|
|
||||||
|
action->connect(action, &QAction::triggered, cb);
|
||||||
|
}
|
49
UI/frontend-plugins/frontend-tools/scripts.hpp
Normal file
49
UI/frontend-plugins/frontend-tools/scripts.hpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include <QWidget>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class Ui_ScriptsTool;
|
||||||
|
|
||||||
|
class ScriptLogWindow : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QString lines;
|
||||||
|
bool bottomScrolled = true;
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScriptLogWindow();
|
||||||
|
~ScriptLogWindow();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void AddLogMsg(int log_level, QString msg);
|
||||||
|
void Clear();
|
||||||
|
void ScrollChanged(int val);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScriptsTool : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Ui_ScriptsTool *ui;
|
||||||
|
QWidget *propertiesView = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScriptsTool();
|
||||||
|
~ScriptsTool();
|
||||||
|
|
||||||
|
void RemoveScript(const char *path);
|
||||||
|
void ReloadScript(const char *path);
|
||||||
|
void RefreshLists();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void on_close_clicked();
|
||||||
|
|
||||||
|
void on_addScripts_clicked();
|
||||||
|
void on_removeScripts_clicked();
|
||||||
|
void on_reloadScripts_clicked();
|
||||||
|
void on_scriptLog_clicked();
|
||||||
|
|
||||||
|
void on_scripts_currentRowChanged(int row);
|
||||||
|
|
||||||
|
void on_pythonPathBrowse_clicked();
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user