UI: OS File Operations Within File Browser
Adds a submenu to the File Browser selected item context menu that allows opening the item or viewing the location in an OS browsing window. On Win32 also allows other actions like editing, searching, opening command prompt, etc. Pull Request: https://projects.blender.org/blender/blender/pulls/104531
This commit is contained in:
@@ -538,6 +538,7 @@ class FILEBROWSER_MT_context_menu(FileBrowserMenu, Menu):
|
||||
layout.operator("file.next", text="Forward")
|
||||
layout.operator("file.parent", text="Go to Parent")
|
||||
layout.operator("file.refresh", text="Refresh")
|
||||
layout.menu("FILEBROWSER_MT_operations_menu")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
||||
@@ -113,6 +113,33 @@ ENUM_OPERATORS(eFileAttributes, FILE_ATTR_HARDLINK);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name External File Operations
|
||||
* \{ */
|
||||
|
||||
typedef enum FileExternalOperation {
|
||||
FILE_EXTERNAL_OPERATION_OPEN = 0,
|
||||
FILE_EXTERNAL_OPERATION_FOLDER_OPEN,
|
||||
/* Following are Windows-only: */
|
||||
FILE_EXTERNAL_OPERATION_EDIT,
|
||||
FILE_EXTERNAL_OPERATION_NEW,
|
||||
FILE_EXTERNAL_OPERATION_FIND,
|
||||
FILE_EXTERNAL_OPERATION_SHOW,
|
||||
FILE_EXTERNAL_OPERATION_PLAY,
|
||||
FILE_EXTERNAL_OPERATION_BROWSE,
|
||||
FILE_EXTERNAL_OPERATION_PREVIEW,
|
||||
FILE_EXTERNAL_OPERATION_PRINT,
|
||||
FILE_EXTERNAL_OPERATION_INSTALL,
|
||||
FILE_EXTERNAL_OPERATION_RUNAS,
|
||||
FILE_EXTERNAL_OPERATION_PROPERTIES,
|
||||
FILE_EXTERNAL_OPERATION_FOLDER_FIND,
|
||||
FILE_EXTERNAL_OPERATION_FOLDER_CMD,
|
||||
} FileExternalOperation;
|
||||
|
||||
bool BLI_file_external_operation_supported(const char *filepath, FileExternalOperation operation);
|
||||
bool BLI_file_external_operation_execute(const char *filepath, FileExternalOperation operation);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Directories
|
||||
* \{ */
|
||||
|
||||
@@ -89,6 +89,11 @@ bool BLI_windows_register_blend_extension(bool background);
|
||||
void BLI_windows_get_default_root_dir(char root_dir[4]);
|
||||
int BLI_windows_get_executable_dir(char *str);
|
||||
|
||||
/* ShellExecute Helpers. */
|
||||
|
||||
bool BLI_windows_external_operation_supported(const char *filepath, const char *operation);
|
||||
bool BLI_windows_external_operation_execute(const char *filepath, const char *operation);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -46,6 +46,71 @@
|
||||
#include "BLI_sys_types.h" /* for intptr_t support */
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#ifdef WIN32
|
||||
/* Text string used as the "verb" for Windows shell operations. */
|
||||
static char *windows_operation_string(FileExternalOperation operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case FILE_EXTERNAL_OPERATION_OPEN:
|
||||
return "open";
|
||||
case FILE_EXTERNAL_OPERATION_FOLDER_OPEN:
|
||||
return "open";
|
||||
case FILE_EXTERNAL_OPERATION_EDIT:
|
||||
return "edit";
|
||||
case FILE_EXTERNAL_OPERATION_NEW:
|
||||
return "new";
|
||||
case FILE_EXTERNAL_OPERATION_FIND:
|
||||
return "find";
|
||||
case FILE_EXTERNAL_OPERATION_SHOW:
|
||||
return "show";
|
||||
case FILE_EXTERNAL_OPERATION_PLAY:
|
||||
return "play";
|
||||
case FILE_EXTERNAL_OPERATION_BROWSE:
|
||||
return "browse";
|
||||
case FILE_EXTERNAL_OPERATION_PREVIEW:
|
||||
return "preview";
|
||||
case FILE_EXTERNAL_OPERATION_PRINT:
|
||||
return "print";
|
||||
case FILE_EXTERNAL_OPERATION_INSTALL:
|
||||
return "install";
|
||||
case FILE_EXTERNAL_OPERATION_RUNAS:
|
||||
return "runas";
|
||||
case FILE_EXTERNAL_OPERATION_PROPERTIES:
|
||||
return "properties";
|
||||
case FILE_EXTERNAL_OPERATION_FOLDER_FIND:
|
||||
return "find";
|
||||
case FILE_EXTERNAL_OPERATION_FOLDER_CMD:
|
||||
return "cmd";
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
bool BLI_file_external_operation_supported(const char *filepath, FileExternalOperation operation)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char *opstring = windows_operation_string(operation);
|
||||
return BLI_windows_external_operation_supported(filepath, opstring);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool BLI_file_external_operation_execute(const char *filepath, FileExternalOperation operation)
|
||||
{
|
||||
#ifdef WIN32
|
||||
char *opstring = windows_operation_string(operation);
|
||||
if (BLI_windows_external_operation_supported(filepath, opstring) &&
|
||||
BLI_windows_external_operation_execute(filepath, opstring)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t BLI_file_zstd_from_mem_at_pos(
|
||||
void *buf, size_t len, FILE *file, size_t file_offset, int compression_level)
|
||||
{
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
# include <conio.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <shlwapi.h>
|
||||
|
||||
# include "MEM_guardedalloc.h"
|
||||
|
||||
# define WIN32_SKIP_HKEY_PROTECTION /* Need to use HKEY. */
|
||||
# include "BLI_fileops.h"
|
||||
# include "BLI_path_util.h"
|
||||
# include "BLI_string.h"
|
||||
# include "BLI_utildefines.h"
|
||||
@@ -178,6 +180,62 @@ bool BLI_windows_register_blend_extension(const bool background)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check the registry to see if there is an operation association to a file
|
||||
* extension. Extension *should almost always contain a dot like ".txt",
|
||||
* but this does allow querying non - extensions *like "Directory", "Drive",
|
||||
* "AllProtocols", etc - anything in Classes with a "shell" branch.
|
||||
*/
|
||||
static bool BLI_windows_file_operation_is_registered(const char *extension, const char *operation)
|
||||
{
|
||||
HKEY hKey;
|
||||
HRESULT hr = AssocQueryKey(ASSOCF_INIT_IGNOREUNKNOWN,
|
||||
ASSOCKEY_SHELLEXECCLASS,
|
||||
(LPCTSTR)extension,
|
||||
(LPCTSTR)operation,
|
||||
&hKey);
|
||||
if (SUCCEEDED(hr)) {
|
||||
RegCloseKey(hKey);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BLI_windows_external_operation_supported(const char *filepath, const char *operation)
|
||||
{
|
||||
if (STREQ(operation, "open") || STREQ(operation, "properties")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (BLI_is_dir(filepath)) {
|
||||
return BLI_windows_file_operation_is_registered("Directory", operation);
|
||||
}
|
||||
|
||||
const char *extension = BLI_path_extension(filepath);
|
||||
return BLI_windows_file_operation_is_registered(extension, operation);
|
||||
}
|
||||
|
||||
bool BLI_windows_external_operation_execute(const char *filepath, char *operation)
|
||||
{
|
||||
WCHAR wpath[FILE_MAX];
|
||||
if (conv_utf_8_to_16(filepath, wpath, ARRAY_SIZE(wpath)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WCHAR woperation[FILE_MAX];
|
||||
if (conv_utf_8_to_16(operation, woperation, ARRAY_SIZE(woperation)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SHELLEXECUTEINFOW shellinfo = {0};
|
||||
shellinfo.cbSize = sizeof(SHELLEXECUTEINFO);
|
||||
shellinfo.fMask = SEE_MASK_INVOKEIDLIST;
|
||||
shellinfo.lpVerb = woperation;
|
||||
shellinfo.lpFile = wpath;
|
||||
shellinfo.nShow = SW_SHOW;
|
||||
|
||||
return ShellExecuteExW(&shellinfo);
|
||||
}
|
||||
|
||||
void BLI_windows_get_default_root_dir(char root[4])
|
||||
{
|
||||
char str[MAX_PATH + 1];
|
||||
|
||||
@@ -66,6 +66,10 @@ void FILE_OT_bookmark_move(struct wmOperatorType *ot);
|
||||
void FILE_OT_reset_recent(wmOperatorType *ot);
|
||||
void FILE_OT_hidedot(struct wmOperatorType *ot);
|
||||
void FILE_OT_execute(struct wmOperatorType *ot);
|
||||
|
||||
void FILE_OT_external_operation(struct wmOperatorType *ot);
|
||||
void file_external_operations_menu_register(void);
|
||||
|
||||
/**
|
||||
* Variation of #FILE_OT_execute that accounts for some mouse specific handling.
|
||||
* Otherwise calls the same logic.
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# include "BLI_winstuff.h"
|
||||
#endif
|
||||
@@ -1768,6 +1770,258 @@ bool file_draw_check_exists(SpaceFile *sfile)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name External operations that can performed on files.
|
||||
* \{ */
|
||||
|
||||
static const EnumPropertyItem file_external_operation[] = {
|
||||
{FILE_EXTERNAL_OPERATION_OPEN, "OPEN", 0, "Open", "Open the file"},
|
||||
{FILE_EXTERNAL_OPERATION_FOLDER_OPEN, "FOLDER_OPEN", 0, "Open Folder", "Open the folder"},
|
||||
{FILE_EXTERNAL_OPERATION_EDIT, "EDIT", 0, "Edit", "Edit the file"},
|
||||
{FILE_EXTERNAL_OPERATION_NEW, "NEW", 0, "New", "Create a new file of this type"},
|
||||
{FILE_EXTERNAL_OPERATION_FIND, "FIND", 0, "Find File", "Search for files of this type"},
|
||||
{FILE_EXTERNAL_OPERATION_SHOW, "SHOW", 0, "Show", "Show this file"},
|
||||
{FILE_EXTERNAL_OPERATION_PLAY, "PLAY", 0, "Play", "Play this file"},
|
||||
{FILE_EXTERNAL_OPERATION_BROWSE, "BROWSE", 0, "Browse", "Browse this file"},
|
||||
{FILE_EXTERNAL_OPERATION_PREVIEW, "PREVIEW", 0, "Preview", "Preview this file"},
|
||||
{FILE_EXTERNAL_OPERATION_PRINT, "PRINT", 0, "Print", "Print this file"},
|
||||
{FILE_EXTERNAL_OPERATION_INSTALL, "INSTALL", 0, "Install", "Install this file"},
|
||||
{FILE_EXTERNAL_OPERATION_RUNAS, "RUNAS", 0, "Run As User", "Run as specific user"},
|
||||
{FILE_EXTERNAL_OPERATION_PROPERTIES,
|
||||
"PROPERTIES",
|
||||
0,
|
||||
"Properties",
|
||||
"Show OS Properties for this item"},
|
||||
{FILE_EXTERNAL_OPERATION_FOLDER_FIND,
|
||||
"FOLDER_FIND",
|
||||
0,
|
||||
"Find in Folder",
|
||||
"Search for items in this folder"},
|
||||
{FILE_EXTERNAL_OPERATION_FOLDER_CMD,
|
||||
"CMD",
|
||||
0,
|
||||
"Command Prompt Here",
|
||||
"Open a command prompt here"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static int file_external_operation_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
|
||||
char filepath[FILE_MAX];
|
||||
RNA_property_string_get(op->ptr, prop, filepath);
|
||||
|
||||
const FileExternalOperation operation = (FileExternalOperation)RNA_enum_get(op->ptr,
|
||||
"operation");
|
||||
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_WAIT);
|
||||
|
||||
#ifdef WIN32
|
||||
if (BLI_file_external_operation_execute(filepath, operation)) {
|
||||
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
#else
|
||||
wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
|
||||
PointerRNA op_props;
|
||||
WM_operator_properties_create_ptr(&op_props, ot);
|
||||
RNA_string_set(&op_props, "filepath", filepath);
|
||||
if (WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props, NULL) ==
|
||||
OPERATOR_FINISHED) {
|
||||
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
#endif
|
||||
|
||||
BKE_reportf(
|
||||
op->reports, RPT_ERROR, "Failure to perform exernal file operation on \"%s\"", filepath);
|
||||
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static char *file_external_operation_description(bContext *UNUSED(C),
|
||||
wmOperatorType *UNUSED(ot),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
const char *description = "";
|
||||
RNA_enum_description(file_external_operation, RNA_enum_get(ptr, "operation"), &description);
|
||||
return BLI_strdup(description);
|
||||
}
|
||||
|
||||
void FILE_OT_external_operation(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "External File Operation";
|
||||
ot->idname = "FILE_OT_external_operation";
|
||||
ot->description = "Perform external operation on a file or folder";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = file_external_operation_exec;
|
||||
ot->get_description = file_external_operation_description;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER; /* No undo! */
|
||||
|
||||
/* properties */
|
||||
prop = RNA_def_string(ot->srna, "filepath", NULL, FILE_MAX, "File or folder path", "");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"operation",
|
||||
file_external_operation,
|
||||
0,
|
||||
"Operation",
|
||||
"Operation to perform on the file or path");
|
||||
}
|
||||
|
||||
static void file_os_operations_menu_item(uiLayout *layout,
|
||||
wmOperatorType *ot,
|
||||
const char *path,
|
||||
FileExternalOperation operation)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (!BLI_file_external_operation_supported(path, operation)) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!ELEM(operation, FILE_EXTERNAL_OPERATION_OPEN, FILE_EXTERNAL_OPERATION_FOLDER_OPEN)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *title = "";
|
||||
RNA_enum_name(file_external_operation, operation, &title);
|
||||
|
||||
PointerRNA props_ptr;
|
||||
uiItemFullO_ptr(layout, ot, title, ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, 0, &props_ptr);
|
||||
RNA_string_set(&props_ptr, "filepath", path);
|
||||
if (operation) {
|
||||
RNA_enum_set(&props_ptr, "operation", operation);
|
||||
}
|
||||
}
|
||||
|
||||
static void file_os_operations_menu_draw(const bContext *C_const, Menu *menu)
|
||||
{
|
||||
bContext *C = (bContext *)C_const;
|
||||
|
||||
/* File browsing only operator (not asset browsing). */
|
||||
if (!ED_operator_file_browsing_active(C)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
|
||||
if (!sfile || !params) {
|
||||
return;
|
||||
}
|
||||
|
||||
char dir[FILE_MAX_LIBEXTRA];
|
||||
if (filelist_islibrary(sfile->files, dir, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int numfiles = filelist_files_ensure(sfile->files);
|
||||
FileDirEntry *fileentry = NULL;
|
||||
int num_selected = 0;
|
||||
|
||||
for (int i = 0; i < numfiles; i++) {
|
||||
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
|
||||
fileentry = filelist_file(sfile->files, i);
|
||||
num_selected++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileentry || num_selected > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
char path[FILE_MAX_LIBEXTRA];
|
||||
filelist_file_get_full_path(sfile->files, fileentry, path);
|
||||
const char *root = filelist_dir(sfile->files);
|
||||
|
||||
uiLayout *layout = menu->layout;
|
||||
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
|
||||
wmOperatorType *ot = WM_operatortype_find("FILE_OT_external_operation", true);
|
||||
|
||||
if (fileentry->typeflag & FILE_TYPE_DIR) {
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_FOLDER_OPEN);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_FOLDER_CMD);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_PROPERTIES);
|
||||
}
|
||||
else {
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_OPEN);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_EDIT);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_NEW);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_FIND);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_SHOW);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_PLAY);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_BROWSE);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_PREVIEW);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_PRINT);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_INSTALL);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_RUNAS);
|
||||
file_os_operations_menu_item(layout, ot, root, FILE_EXTERNAL_OPERATION_FOLDER_OPEN);
|
||||
file_os_operations_menu_item(layout, ot, root, FILE_EXTERNAL_OPERATION_FOLDER_CMD);
|
||||
file_os_operations_menu_item(layout, ot, path, FILE_EXTERNAL_OPERATION_PROPERTIES);
|
||||
}
|
||||
}
|
||||
|
||||
static bool file_os_operations_menu_poll(const bContext *C_const, MenuType *UNUSED(mt))
|
||||
{
|
||||
bContext *C = (bContext *)C_const;
|
||||
|
||||
/* File browsing only operator (not asset browsing). */
|
||||
if (!ED_operator_file_browsing_active(C)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpaceFile *sfile = CTX_wm_space_file(C);
|
||||
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
|
||||
|
||||
if (sfile && params) {
|
||||
char dir[FILE_MAX_LIBEXTRA];
|
||||
if (filelist_islibrary(sfile->files, dir, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int numfiles = filelist_files_ensure(sfile->files);
|
||||
int num_selected = 0;
|
||||
for (int i = 0; i < numfiles; i++) {
|
||||
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
|
||||
num_selected++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_selected > 1) {
|
||||
CTX_wm_operator_poll_msg_set(C, "More than one item is selected");
|
||||
}
|
||||
else if (num_selected < 1) {
|
||||
CTX_wm_operator_poll_msg_set(C, "No items are selected");
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void file_external_operations_menu_register(void)
|
||||
{
|
||||
MenuType *mt;
|
||||
|
||||
mt = MEM_callocN(sizeof(MenuType), "spacetype file menu file operations");
|
||||
strcpy(mt->idname, "FILEBROWSER_MT_operations_menu");
|
||||
strcpy(mt->label, N_("External"));
|
||||
strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
|
||||
mt->draw = file_os_operations_menu_draw;
|
||||
mt->poll = file_os_operations_menu_poll;
|
||||
WM_menutype_add(mt);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Execute File Window Operator
|
||||
* \{ */
|
||||
|
||||
@@ -613,6 +613,7 @@ static void file_operatortypes(void)
|
||||
WM_operatortype_append(FILE_OT_start_filter);
|
||||
WM_operatortype_append(FILE_OT_edit_directory_path);
|
||||
WM_operatortype_append(FILE_OT_view_selected);
|
||||
WM_operatortype_append(FILE_OT_external_operation);
|
||||
}
|
||||
|
||||
/* NOTE: do not add .blend file reading on this level */
|
||||
@@ -1063,6 +1064,7 @@ void ED_spacetype_file(void)
|
||||
art->draw = file_tools_region_draw;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
file_tool_props_region_panels_register(art);
|
||||
file_external_operations_menu_register();
|
||||
|
||||
BKE_spacetype_register(st);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user