Compare commits

..

6 Commits

Author SHA1 Message Date
6a0f9cdbed make property spreadsheet a bit more generic 2021-03-05 13:55:21 +01:00
ea81fcbc96 show a custom property 2021-03-05 13:48:22 +01:00
8ff310861c cleanup 2021-03-05 13:36:51 +01:00
46194c68cf draw rna properties 2021-03-05 12:54:56 +01:00
a32bf199d4 support drawing ints 2021-03-05 11:38:50 +01:00
77136bd7b3 initial python spreadsheet 2021-03-05 11:35:56 +01:00
5 changed files with 283 additions and 29 deletions

View File

@@ -0,0 +1,61 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
class SpreadsheetDrawer:
def get_row_amount(self):
return 0
def get_column_amount(self):
return 0
def get_top_row_cell(self, column_index):
return None
def get_left_column_cell(self, row_index):
return None
def get_content_cell(self, row_index, column_index):
return None
class PropertiesSpreadsheet(SpreadsheetDrawer):
def __init__(self, owners, property_names):
self.owners = owners
self.property_names = property_names
def get_row_amount(self):
return len(self.owners)
def get_column_amount(self):
return len(self.property_names)
def get_top_row_cell(self, column_index):
return self.property_names[column_index]
def get_left_column_cell(self, row_index):
return row_index
def get_content_cell(self, row_index, column_index):
owner = self.owners[row_index]
return (owner, self.property_names[column_index])
def get_spreadsheet_drawer(spreadsheet_space: bpy.types.SpaceSpreadsheet):
prop_names = ["name", "location.x", "location.y", "location.z", '["a"]']
return PropertiesSpreadsheet(list(bpy.context.selected_objects), prop_names)

View File

@@ -31,18 +31,25 @@ set(INC
../../../../intern/guardedalloc
)
set(INC_SYS
${PYTHON_INCLUDE_DIRS}
)
set(SRC
space_spreadsheet.cc
spreadsheet_draw.cc
spreadsheet_from_geometry.cc
spreadsheet_from_python.cc
spreadsheet_ops.cc
spreadsheet_draw.hh
spreadsheet_from_geometry.hh
spreadsheet_from_python.hh
spreadsheet_intern.hh
)
set(LIB
)
blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@@ -43,6 +43,7 @@
#include "bmesh.h"
#include "spreadsheet_from_geometry.hh"
#include "spreadsheet_from_python.hh"
#include "spreadsheet_intern.hh"
using namespace blender::ed::spreadsheet;
@@ -102,40 +103,12 @@ static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
WM_event_add_keymap_handler(&region->handlers, keymap);
}
static ID *get_used_id(const bContext *C)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
if (sspreadsheet->pinned_id != nullptr) {
return sspreadsheet->pinned_id;
}
Object *active_object = CTX_data_active_object(C);
return (ID *)active_object;
}
class FallbackSpreadsheetDrawer : public SpreadsheetDrawer {
};
static std::unique_ptr<SpreadsheetDrawer> generate_spreadsheet_drawer(const bContext *C)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ID *used_id = get_used_id(C);
if (used_id == nullptr) {
return {};
}
const ID_Type id_type = GS(used_id->name);
if (id_type != ID_OB) {
return {};
}
Object *object_orig = (Object *)used_id;
if (object_orig->type != OB_MESH) {
return {};
}
Object *object_eval = DEG_get_evaluated_object(depsgraph, object_orig);
if (object_eval == nullptr) {
return {};
}
return spreadsheet_drawer_from_geometry_attributes(C, object_eval);
return spreadsheet_drawer_from_python(C);
}
static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)

View File

@@ -0,0 +1,186 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <Python.h>
#include "RNA_access.h"
#include "DNA_space_types.h"
#include "BKE_context.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "../../python/intern/bpy_rna.h"
#include "spreadsheet_from_python.hh"
namespace blender::ed::spreadsheet {
class PythonSpreadsheetDrawer : public SpreadsheetDrawer {
private:
PyObject *py_drawer_;
public:
PythonSpreadsheetDrawer(PyObject *py_drawer) : py_drawer_(py_drawer)
{
BLI_assert(py_drawer_ != nullptr);
BLI_assert(py_drawer_ != Py_None);
Py_INCREF(py_drawer_);
PyObject *py_column_amount = PyObject_CallMethod(py_drawer_, "get_column_amount", "");
this->tot_columns = PyLong_AsLong(py_column_amount);
Py_DECREF(py_column_amount);
PyObject *py_row_amount = PyObject_CallMethod(py_drawer_, "get_row_amount", "");
this->tot_rows = PyLong_AsLong(py_row_amount);
Py_DecRef(py_row_amount);
}
~PythonSpreadsheetDrawer() override
{
PyGILState_STATE gilstate = PyGILState_Ensure();
Py_DECREF(py_drawer_);
PyGILState_Release(gilstate);
}
void draw_top_row_cell(int column_index, const CellDrawParams &params) const override
{
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *py_cell_content = PyObject_CallMethod(
py_drawer_, "get_top_row_cell", "i", column_index);
this->draw_cell_content(params, py_cell_content);
Py_DecRef(py_cell_content);
PyGILState_Release(gilstate);
}
void draw_left_column_cell(int row_index, const CellDrawParams &params) const override
{
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *py_cell_content = PyObject_CallMethod(
py_drawer_, "get_left_column_cell", "i", row_index);
this->draw_cell_content(params, py_cell_content);
Py_DecRef(py_cell_content);
PyGILState_Release(gilstate);
}
void draw_content_cell(int row_index,
int column_index,
const CellDrawParams &params) const override
{
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *py_cell_content = PyObject_CallMethod(
py_drawer_, "get_content_cell", "ii", row_index, column_index);
this->draw_cell_content(params, py_cell_content);
Py_DecRef(py_cell_content);
PyGILState_Release(gilstate);
}
private:
void draw_cell_content(const CellDrawParams &params, PyObject *py_cell_content) const
{
if (py_cell_content == nullptr) {
return;
}
if (py_cell_content == Py_None) {
return;
}
if (PyUnicode_Check(py_cell_content)) {
const char *str = PyUnicode_AsUTF8(py_cell_content);
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
ICON_NONE,
str,
params.xmin,
params.ymin,
params.width,
params.height,
nullptr,
0,
0,
0,
0,
nullptr);
}
if (PyLong_Check(py_cell_content)) {
const int value = PyLong_AsLong(py_cell_content);
const std::string value_str = std::to_string(value);
uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
ICON_NONE,
value_str.c_str(),
params.xmin,
params.ymin,
params.width,
params.height,
nullptr,
0,
0,
0,
0,
nullptr);
}
if (PyTuple_Check(py_cell_content)) {
PyObject *py_rna_ptr = PyTuple_GetItem(py_cell_content, 0);
PyObject *py_prop_path = PyTuple_GetItem(py_cell_content, 1);
const char *prop_path = PyUnicode_AsUTF8(py_prop_path);
BPy_StructRNA *py_struct_rna = (BPy_StructRNA *)py_rna_ptr;
PointerRNA ptr;
PropertyRNA *prop = nullptr;
int index;
RNA_path_resolve_full(&py_struct_rna->ptr, prop_path, &ptr, &prop, &index);
if (prop != nullptr) {
uiDefAutoButR(params.block,
&ptr,
prop,
index,
"",
ICON_NONE,
params.xmin,
params.ymin,
params.width,
params.height);
}
}
}
};
std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_python(const bContext *C)
{
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
PointerRNA sspreadsheet_rna;
RNA_pointer_create(nullptr, &RNA_SpaceSpreadsheet, sspreadsheet, &sspreadsheet_rna);
std::unique_ptr<SpreadsheetDrawer> drawer;
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *py_module = PyImport_ImportModule("bpy_spreadsheet");
PyObject *py_get_drawer_func = PyObject_GetAttrString(py_module, "get_spreadsheet_drawer");
PyObject *py_sspreadsheet = pyrna_struct_CreatePyObject(&sspreadsheet_rna);
PyObject *py_drawer = PyObject_CallFunction(py_get_drawer_func, "O", py_sspreadsheet);
if (py_drawer != Py_None) {
drawer = std::make_unique<PythonSpreadsheetDrawer>(py_drawer);
}
Py_DECREF(py_drawer);
Py_DECREF(py_sspreadsheet);
PyGILState_Release(gilstate);
return drawer;
}
} // namespace blender::ed::spreadsheet

View File

@@ -0,0 +1,27 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include "spreadsheet_draw.hh"
struct bContext;
namespace blender::ed::spreadsheet {
std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_python(const bContext *C);
} // namespace blender::ed::spreadsheet