Compare commits
66 Commits
temp-outli
...
temp-sprea
Author | SHA1 | Date | |
---|---|---|---|
6a0f9cdbed | |||
ea81fcbc96 | |||
8ff310861c | |||
46194c68cf | |||
a32bf199d4 | |||
77136bd7b3 | |||
381e2d4dc2 | |||
cf6208382e | |||
b837933b17 | |||
3ca094651b | |||
ad8238cb51 | |||
9c58324b78 | |||
f78dd85077 | |||
8ce62fedd8 | |||
fba3d696ee | |||
ea0bfde339 | |||
7ab29c748a | |||
be36c4d37d | |||
c5bf114d78 | |||
51c844d69b | |||
e0ef38f3ac | |||
8451fa3125 | |||
c0b8a767b4 | |||
cb8dd9905a | |||
4df7e6047b | |||
b2774b03b9 | |||
81d4e4d35e | |||
1e6d38133e | |||
6e261f79ef | |||
a977ed1920 | |||
83ed51c2f1 | |||
fa62b24b57 | |||
18d99cd5fb | |||
cc3e6c4950 | |||
5a71c3cb56 | |||
e2cf5b8b2e | |||
e67275538a | |||
179dfdccd2 | |||
17615ab5aa | |||
1b34d6cd79 | |||
e7e3f17c49 | |||
10804043a5 | |||
b79cd1cb03 | |||
7f9f6ac29f | |||
d829a0a607 | |||
a0191eb889 | |||
1868880e7a | |||
247707c52a | |||
64ddb1c8f2 | |||
70b0b63d7b | |||
c4b67853bd | |||
67c2ef5242 | |||
8568bed752 | |||
0ad34e603c | |||
2e8d77967e | |||
525819b1af | |||
eb6b26192d | |||
27373011de | |||
ced130f849 | |||
6ff897157c | |||
73872fd0e0 | |||
794c0a09eb | |||
886d28f342 | |||
6989349251 | |||
eedc06b6b2 | |||
ea58786120 |
@@ -1009,6 +1009,34 @@ const bTheme U_theme_default = {
|
||||
.facedot_size = 4,
|
||||
.gp_vertex_size = 3,
|
||||
},
|
||||
.space_spreadsheet = {
|
||||
.back = RGBA(0x28282800),
|
||||
.title = RGBA(0xffffffff),
|
||||
.text = RGBA(0xe6e6e6ff),
|
||||
.text_hi = RGBA(0xffffffff),
|
||||
.header = RGBA(0x2e2e2eff),
|
||||
.header_text = RGBA(0xeeeeeeff),
|
||||
.header_text_hi = RGBA(0xffffffff),
|
||||
.tab_active = RGBA(0x4b4b4bff),
|
||||
.tab_inactive = RGBA(0x2b2b2bff),
|
||||
.tab_back = RGBA(0x232323ff),
|
||||
.tab_outline = RGBA(0x232323ff),
|
||||
.button = RGBA(0x4b4b4bff),
|
||||
.button_title = RGBA(0xffffffff),
|
||||
.button_text = RGBA(0xe5e5e5ff),
|
||||
.button_text_hi = RGBA(0xffffffff),
|
||||
.execution_buts = RGBA(0x444444ff),
|
||||
.panelcolors = {
|
||||
.header = RGBA(0x4b4b4bff),
|
||||
.back = RGBA(0x404040ff),
|
||||
.sub_back = RGBA(0x0000003e),
|
||||
},
|
||||
.hilite = RGBA(0x4f76b3ff),
|
||||
.vertex_size = 3,
|
||||
.outline_width = 1,
|
||||
.facedot_size = 4,
|
||||
.row_alternate = RGBA(0xffffff07),
|
||||
},
|
||||
.tarm = {
|
||||
{
|
||||
.solid = RGBA(0x9a0000ff),
|
||||
|
61
release/scripts/modules/bpy_spreadsheet.py
Normal file
61
release/scripts/modules/bpy_spreadsheet.py
Normal 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)
|
@@ -1316,6 +1316,42 @@
|
||||
</space>
|
||||
</ThemeStatusBar>
|
||||
</statusbar>
|
||||
<spreadsheet>
|
||||
<ThemeSpreadsheet
|
||||
row_alternate="#ffffff0f"
|
||||
>
|
||||
<space>
|
||||
<ThemeSpaceGeneric
|
||||
back="#999999"
|
||||
title="#000000"
|
||||
text="#000000"
|
||||
text_hi="#ffffff"
|
||||
header="#adadadff"
|
||||
header_text="#000000"
|
||||
header_text_hi="#ffffff"
|
||||
button="#999999e6"
|
||||
button_title="#1a1a1a"
|
||||
button_text="#000000"
|
||||
button_text_hi="#ffffff"
|
||||
navigation_bar="#00000000"
|
||||
execution_buts="#999999e6"
|
||||
tab_active="#6697e6"
|
||||
tab_inactive="#cccccc"
|
||||
tab_back="#999999ff"
|
||||
tab_outline="#999999"
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
</ThemeSpaceGeneric>
|
||||
</space>
|
||||
</ThemeSpreadsheet>
|
||||
</spreadsheet>
|
||||
<bone_color_sets>
|
||||
<ThemeBoneColorSet
|
||||
normal="#9a0000"
|
||||
|
@@ -45,6 +45,7 @@ _modules = [
|
||||
"rigidbody",
|
||||
"screen_play_rendered_anim",
|
||||
"sequencer",
|
||||
"spreadsheet",
|
||||
"userpref",
|
||||
"uvcalc_follow_active",
|
||||
"uvcalc_lightmap",
|
||||
|
47
release/scripts/startup/bl_operators/spreadsheet.py
Normal file
47
release/scripts/startup/bl_operators/spreadsheet.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# ##### 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 #####
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import bpy
|
||||
|
||||
class SPREADSHEET_OT_toggle_pin(bpy.types.Operator):
|
||||
'''Turn on or off pinning'''
|
||||
bl_idname = "spreadsheet.toggle_pin"
|
||||
bl_label = "Toggle Pin"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
space = context.space_data
|
||||
return space and space.type == 'SPREADSHEET'
|
||||
|
||||
def execute(self, context):
|
||||
space = context.space_data
|
||||
|
||||
if space.pinned_id:
|
||||
space.pinned_id = None
|
||||
else:
|
||||
space.pinned_id = context.active_object
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
classes = (
|
||||
SPREADSHEET_OT_toggle_pin,
|
||||
)
|
@@ -86,6 +86,7 @@ _modules = [
|
||||
"space_outliner",
|
||||
"space_properties",
|
||||
"space_sequencer",
|
||||
"space_spreadsheet",
|
||||
"space_statusbar",
|
||||
"space_text",
|
||||
"space_time",
|
||||
|
52
release/scripts/startup/bl_ui/space_spreadsheet.py
Normal file
52
release/scripts/startup/bl_ui/space_spreadsheet.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# ##### 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 SPREADSHEET_HT_header(bpy.types.Header):
|
||||
bl_space_type = 'SPREADSHEET'
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
space = context.space_data
|
||||
|
||||
layout.template_header()
|
||||
|
||||
pinned_id = space.pinned_id
|
||||
used_id = pinned_id if pinned_id else context.active_object
|
||||
|
||||
if used_id:
|
||||
layout.label(text=used_id.name, icon="OBJECT_DATA")
|
||||
|
||||
layout.operator("spreadsheet.toggle_pin", text="", icon='PINNED' if pinned_id else 'UNPINNED', emboss=False)
|
||||
|
||||
layout.separator_spacer()
|
||||
|
||||
if isinstance(used_id, bpy.types.Object) and used_id.mode == 'EDIT':
|
||||
layout.prop(space, "show_only_selected", text="Selected Only")
|
||||
|
||||
|
||||
classes = (
|
||||
SPREADSHEET_HT_header,
|
||||
)
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
from bpy.utils import register_class
|
||||
for cls in classes:
|
||||
register_class(cls)
|
@@ -197,6 +197,7 @@ struct SpaceInfo *CTX_wm_space_info(const bContext *C);
|
||||
struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C);
|
||||
struct SpaceClip *CTX_wm_space_clip(const bContext *C);
|
||||
struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C);
|
||||
struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C);
|
||||
|
||||
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
|
||||
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
|
||||
|
@@ -914,6 +914,15 @@ struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C)
|
||||
{
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
if (area && area->spacetype == SPACE_SPREADSHEET) {
|
||||
return area->spacedata.first;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
|
||||
{
|
||||
C->wm.manager = wm;
|
||||
|
@@ -224,6 +224,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
|
||||
BKE_LIB_FOREACHID_PROCESS(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE);
|
||||
break;
|
||||
}
|
||||
case SPACE_SPREADSHEET: {
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
|
||||
BKE_LIB_FOREACHID_PROCESS_ID(data, sspreadsheet->pinned_id, IDWALK_CB_NOP);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1342,6 +1348,9 @@ static void write_area_regions(BlendWriter *writer, ScrArea *area)
|
||||
else if (sl->spacetype == SPACE_INFO) {
|
||||
BLO_write_struct(writer, SpaceInfo, sl);
|
||||
}
|
||||
else if (sl->spacetype == SPACE_SPREADSHEET) {
|
||||
BLO_write_struct(writer, SpaceSpreadsheet, sl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1904,6 +1913,11 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr
|
||||
BLO_read_id_address(reader, parent_id->lib, &sclip->mask_info.mask);
|
||||
break;
|
||||
}
|
||||
case SPACE_SPREADSHEET: {
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
BLO_read_id_address(reader, parent_id->lib, &sspreadsheet->pinned_id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@@ -282,6 +282,8 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
|
||||
FROM_DEFAULT_V4_UCHAR(space_info.info_property);
|
||||
FROM_DEFAULT_V4_UCHAR(space_info.info_error);
|
||||
FROM_DEFAULT_V4_UCHAR(space_info.info_operator);
|
||||
|
||||
btheme->space_spreadsheet = btheme->space_file;
|
||||
}
|
||||
|
||||
#undef FROM_DEFAULT_V4_UCHAR
|
||||
|
@@ -53,6 +53,7 @@ if(WITH_BLENDER)
|
||||
add_subdirectory(space_outliner)
|
||||
add_subdirectory(space_script)
|
||||
add_subdirectory(space_sequencer)
|
||||
add_subdirectory(space_spreadsheet)
|
||||
add_subdirectory(space_statusbar)
|
||||
add_subdirectory(space_text)
|
||||
add_subdirectory(space_topbar)
|
||||
|
@@ -55,6 +55,7 @@ void ED_spacetype_userpref(void);
|
||||
void ED_spacetype_clip(void);
|
||||
void ED_spacetype_statusbar(void);
|
||||
void ED_spacetype_topbar(void);
|
||||
void ED_spacetype_spreadsheet(void);
|
||||
|
||||
/* calls for instancing and freeing spacetype static data
|
||||
* called in WM_init_exit */
|
||||
|
@@ -642,6 +642,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create(
|
||||
SPACE_MENU_NOP(SPACE_SCRIPT);
|
||||
SPACE_MENU_NOP(SPACE_STATUSBAR);
|
||||
SPACE_MENU_NOP(SPACE_TOPBAR);
|
||||
SPACE_MENU_NOP(SPACE_SPREADSHEET);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < idname_array_len; i++) {
|
||||
|
@@ -160,6 +160,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
|
||||
case SPACE_STATUSBAR:
|
||||
ts = &btheme->space_statusbar;
|
||||
break;
|
||||
case SPACE_SPREADSHEET:
|
||||
ts = &btheme->space_spreadsheet;
|
||||
break;
|
||||
default:
|
||||
ts = &btheme->space_view3d;
|
||||
break;
|
||||
|
@@ -50,6 +50,7 @@ set(LIB
|
||||
bf_editor_space_outliner
|
||||
bf_editor_space_script
|
||||
bf_editor_space_sequencer
|
||||
bf_editor_space_spreadsheet
|
||||
bf_editor_space_statusbar
|
||||
bf_editor_space_text
|
||||
bf_editor_space_topbar
|
||||
|
@@ -95,6 +95,7 @@ void ED_spacetypes_init(void)
|
||||
ED_spacetype_clip();
|
||||
ED_spacetype_statusbar();
|
||||
ED_spacetype_topbar();
|
||||
ED_spacetype_spreadsheet();
|
||||
|
||||
/* Register operator types for screen and all spaces. */
|
||||
ED_operatortypes_userpref();
|
||||
|
55
source/blender/editors/space_spreadsheet/CMakeLists.txt
Normal file
55
source/blender/editors/space_spreadsheet/CMakeLists.txt
Normal file
@@ -0,0 +1,55 @@
|
||||
# ***** 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 *****
|
||||
|
||||
set(INC
|
||||
../include
|
||||
../../blenkernel
|
||||
../../blenlib
|
||||
../../blenfont
|
||||
../../bmesh
|
||||
../../depsgraph
|
||||
../../functions
|
||||
../../gpu
|
||||
../../makesdna
|
||||
../../makesrna
|
||||
../../windowmanager
|
||||
../../../../intern/glew-mx
|
||||
../../../../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}")
|
242
source/blender/editors/space_spreadsheet/space_spreadsheet.cc
Normal file
242
source/blender/editors/space_spreadsheet/space_spreadsheet.cc
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* 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 <cstring>
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "ED_screen.h"
|
||||
#include "ED_space_api.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "BLF_api.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
#include "spreadsheet_from_geometry.hh"
|
||||
#include "spreadsheet_from_python.hh"
|
||||
#include "spreadsheet_intern.hh"
|
||||
|
||||
using namespace blender::ed::spreadsheet;
|
||||
|
||||
static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
|
||||
{
|
||||
SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet),
|
||||
"spreadsheet space");
|
||||
spreadsheet_space->spacetype = SPACE_SPREADSHEET;
|
||||
|
||||
{
|
||||
/* header */
|
||||
ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
|
||||
BLI_addtail(&spreadsheet_space->regionbase, region);
|
||||
region->regiontype = RGN_TYPE_HEADER;
|
||||
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
|
||||
}
|
||||
|
||||
{
|
||||
/* main window */
|
||||
ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
|
||||
BLI_addtail(&spreadsheet_space->regionbase, region);
|
||||
region->regiontype = RGN_TYPE_WINDOW;
|
||||
}
|
||||
|
||||
return (SpaceLink *)spreadsheet_space;
|
||||
}
|
||||
|
||||
static void spreadsheet_free(SpaceLink *UNUSED(sl))
|
||||
{
|
||||
}
|
||||
|
||||
static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
|
||||
{
|
||||
}
|
||||
|
||||
static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
|
||||
{
|
||||
return (SpaceLink *)MEM_dupallocN(sl);
|
||||
}
|
||||
|
||||
static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf))
|
||||
{
|
||||
}
|
||||
|
||||
static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
|
||||
{
|
||||
region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM;
|
||||
region->v2d.align = V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y;
|
||||
region->v2d.keepzoom = V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT;
|
||||
region->v2d.keeptot = V2D_KEEPTOT_STRICT;
|
||||
region->v2d.minzoom = region->v2d.maxzoom = 1.0f;
|
||||
|
||||
UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
|
||||
|
||||
wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0);
|
||||
WM_event_add_keymap_handler(®ion->handlers, keymap);
|
||||
}
|
||||
|
||||
class FallbackSpreadsheetDrawer : public SpreadsheetDrawer {
|
||||
};
|
||||
|
||||
static std::unique_ptr<SpreadsheetDrawer> generate_spreadsheet_drawer(const bContext *C)
|
||||
{
|
||||
return spreadsheet_drawer_from_python(C);
|
||||
}
|
||||
|
||||
static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
|
||||
{
|
||||
std::unique_ptr<SpreadsheetDrawer> drawer = generate_spreadsheet_drawer(C);
|
||||
if (!drawer) {
|
||||
drawer = std::make_unique<FallbackSpreadsheetDrawer>();
|
||||
}
|
||||
draw_spreadsheet_in_region(C, region, *drawer);
|
||||
}
|
||||
|
||||
static void spreadsheet_main_region_listener(const wmRegionListenerParams *params)
|
||||
{
|
||||
ARegion *region = params->region;
|
||||
wmNotifier *wmn = params->notifier;
|
||||
|
||||
switch (wmn->category) {
|
||||
case NC_SCENE: {
|
||||
switch (wmn->data) {
|
||||
case ND_MODE:
|
||||
case ND_OB_ACTIVE: {
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NC_OBJECT: {
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
case NC_SPACE: {
|
||||
if (wmn->data == ND_SPACE_SPREADSHEET) {
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NC_GEOM: {
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
|
||||
{
|
||||
ED_region_header_init(region);
|
||||
}
|
||||
|
||||
static void spreadsheet_header_region_draw(const bContext *C, ARegion *region)
|
||||
{
|
||||
ED_region_header(C, region);
|
||||
}
|
||||
|
||||
static void spreadsheet_header_region_free(ARegion *UNUSED(region))
|
||||
{
|
||||
}
|
||||
|
||||
static void spreadsheet_header_region_listener(const wmRegionListenerParams *params)
|
||||
{
|
||||
ARegion *region = params->region;
|
||||
wmNotifier *wmn = params->notifier;
|
||||
|
||||
switch (wmn->category) {
|
||||
case NC_SCENE: {
|
||||
switch (wmn->data) {
|
||||
case ND_MODE:
|
||||
case ND_OB_ACTIVE: {
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NC_OBJECT: {
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
case NC_SPACE: {
|
||||
if (wmn->data == ND_SPACE_SPREADSHEET) {
|
||||
ED_region_tag_redraw(region);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NC_GEOM: {
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ED_spacetype_spreadsheet(void)
|
||||
{
|
||||
SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
|
||||
ARegionType *art;
|
||||
|
||||
st->spaceid = SPACE_SPREADSHEET;
|
||||
strncpy(st->name, "Spreadsheet", BKE_ST_MAXNAME);
|
||||
|
||||
st->create = spreadsheet_create;
|
||||
st->free = spreadsheet_free;
|
||||
st->init = spreadsheet_init;
|
||||
st->duplicate = spreadsheet_duplicate;
|
||||
st->operatortypes = spreadsheet_operatortypes;
|
||||
st->keymap = spreadsheet_keymap;
|
||||
|
||||
/* regions: main window */
|
||||
art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
|
||||
art->regionid = RGN_TYPE_WINDOW;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
|
||||
|
||||
art->init = spreadsheet_main_region_init;
|
||||
art->draw = spreadsheet_main_region_draw;
|
||||
art->listener = spreadsheet_main_region_listener;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
/* regions: header */
|
||||
art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region");
|
||||
art->regionid = RGN_TYPE_HEADER;
|
||||
art->prefsizey = HEADERY;
|
||||
art->keymapflag = 0;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
|
||||
|
||||
art->init = spreadsheet_header_region_init;
|
||||
art->draw = spreadsheet_header_region_draw;
|
||||
art->free = spreadsheet_header_region_free;
|
||||
art->listener = spreadsheet_header_region_listener;
|
||||
BLI_addhead(&st->regiontypes, art);
|
||||
|
||||
BKE_spacetype_register(st);
|
||||
}
|
304
source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
Normal file
304
source/blender/editors/space_spreadsheet/spreadsheet_draw.cc
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* 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 "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "GPU_immediate.h"
|
||||
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "BLI_rect.h"
|
||||
|
||||
#include "spreadsheet_draw.hh"
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
SpreadsheetDrawer::SpreadsheetDrawer()
|
||||
{
|
||||
left_column_width = UI_UNIT_X * 2;
|
||||
top_row_height = UI_UNIT_Y * 1.1f;
|
||||
row_height = UI_UNIT_Y;
|
||||
}
|
||||
|
||||
SpreadsheetDrawer::~SpreadsheetDrawer() = default;
|
||||
|
||||
void SpreadsheetDrawer::draw_top_row_cell(int UNUSED(column_index),
|
||||
const CellDrawParams &UNUSED(params)) const
|
||||
{
|
||||
}
|
||||
|
||||
void SpreadsheetDrawer::draw_left_column_cell(int UNUSED(row_index),
|
||||
const CellDrawParams &UNUSED(params)) const
|
||||
{
|
||||
}
|
||||
|
||||
void SpreadsheetDrawer::draw_content_cell(int UNUSED(row_index),
|
||||
int UNUSED(column_index),
|
||||
const CellDrawParams &UNUSED(params)) const
|
||||
{
|
||||
}
|
||||
|
||||
int SpreadsheetDrawer::column_width(int UNUSED(column_index)) const
|
||||
{
|
||||
return 5 * UI_UNIT_X;
|
||||
}
|
||||
|
||||
static void draw_index_column_background(const uint pos,
|
||||
const ARegion *region,
|
||||
const SpreadsheetDrawer &drawer)
|
||||
{
|
||||
immUniformThemeColorShade(TH_BACK, 11);
|
||||
immRecti(pos, 0, region->winy - drawer.top_row_height, drawer.left_column_width, 0);
|
||||
}
|
||||
|
||||
static void draw_alternating_row_overlay(const uint pos,
|
||||
const int scroll_offset_y,
|
||||
const ARegion *region,
|
||||
const SpreadsheetDrawer &drawer)
|
||||
{
|
||||
immUniformThemeColor(TH_ROW_ALTERNATE);
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
BLI_assert(drawer.row_height > 0);
|
||||
const int row_pair_height = drawer.row_height * 2;
|
||||
const int row_top_y = region->winy - drawer.top_row_height - scroll_offset_y % row_pair_height;
|
||||
for (const int i : IndexRange(region->winy / row_pair_height + 1)) {
|
||||
int x_left = 0;
|
||||
int x_right = region->winx;
|
||||
int y_top = row_top_y - i * row_pair_height - drawer.row_height;
|
||||
int y_bottom = y_top - drawer.row_height;
|
||||
y_top = std::min(y_top, region->winy - drawer.top_row_height);
|
||||
y_bottom = std::min(y_bottom, region->winy - drawer.top_row_height);
|
||||
immRecti(pos, x_left, y_top, x_right, y_bottom);
|
||||
}
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
static void draw_top_row_background(const uint pos,
|
||||
const ARegion *region,
|
||||
const SpreadsheetDrawer &drawer)
|
||||
{
|
||||
immUniformThemeColorShade(TH_BACK, 11);
|
||||
immRecti(pos, 0, region->winy, region->winx, region->winy - drawer.top_row_height);
|
||||
}
|
||||
|
||||
static void draw_separator_lines(const uint pos,
|
||||
const int scroll_offset_x,
|
||||
const ARegion *region,
|
||||
const SpreadsheetDrawer &drawer)
|
||||
{
|
||||
immUniformThemeColorShade(TH_BACK, -11);
|
||||
|
||||
immBeginAtMost(GPU_PRIM_LINES, drawer.tot_columns * 2 + 4);
|
||||
|
||||
/* Left column line. */
|
||||
immVertex2i(pos, drawer.left_column_width, region->winy);
|
||||
immVertex2i(pos, drawer.left_column_width, 0);
|
||||
|
||||
/* Top row line. */
|
||||
immVertex2i(pos, 0, region->winy - drawer.top_row_height);
|
||||
immVertex2i(pos, region->winx, region->winy - drawer.top_row_height);
|
||||
|
||||
/* Column separator lines. */
|
||||
int line_x = drawer.left_column_width - scroll_offset_x;
|
||||
for (const int column_index : IndexRange(drawer.tot_columns)) {
|
||||
const int column_width = drawer.column_width(column_index);
|
||||
line_x += column_width;
|
||||
if (line_x >= drawer.left_column_width) {
|
||||
immVertex2i(pos, line_x, region->winy);
|
||||
immVertex2i(pos, line_x, 0);
|
||||
}
|
||||
}
|
||||
immEnd();
|
||||
}
|
||||
|
||||
static void get_visible_rows(const SpreadsheetDrawer &drawer,
|
||||
const ARegion *region,
|
||||
const int scroll_offset_y,
|
||||
int *r_first_row,
|
||||
int *r_max_visible_rows)
|
||||
{
|
||||
*r_first_row = -scroll_offset_y / drawer.row_height;
|
||||
*r_max_visible_rows = region->winy / drawer.row_height + 1;
|
||||
}
|
||||
|
||||
static void draw_left_column_content(const int scroll_offset_y,
|
||||
const bContext *C,
|
||||
ARegion *region,
|
||||
const SpreadsheetDrawer &drawer)
|
||||
{
|
||||
GPU_scissor_test(true);
|
||||
GPU_scissor(0, 0, drawer.left_column_width, region->winy - drawer.top_row_height);
|
||||
|
||||
uiBlock *left_column_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
|
||||
int first_row, max_visible_rows;
|
||||
get_visible_rows(drawer, region, scroll_offset_y, &first_row, &max_visible_rows);
|
||||
for (const int row_index : IndexRange(first_row, max_visible_rows)) {
|
||||
if (row_index >= drawer.tot_rows) {
|
||||
break;
|
||||
}
|
||||
CellDrawParams params;
|
||||
params.block = left_column_block;
|
||||
params.xmin = 0;
|
||||
params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
|
||||
scroll_offset_y;
|
||||
params.width = drawer.left_column_width;
|
||||
params.height = drawer.row_height;
|
||||
drawer.draw_left_column_cell(row_index, params);
|
||||
}
|
||||
|
||||
UI_block_end(C, left_column_block);
|
||||
UI_block_draw(C, left_column_block);
|
||||
|
||||
GPU_scissor_test(false);
|
||||
}
|
||||
|
||||
static void draw_top_row_content(const bContext *C,
|
||||
ARegion *region,
|
||||
const SpreadsheetDrawer &drawer,
|
||||
const int scroll_offset_x)
|
||||
{
|
||||
GPU_scissor_test(true);
|
||||
GPU_scissor(drawer.left_column_width + 1,
|
||||
region->winy - drawer.top_row_height,
|
||||
region->winx - drawer.left_column_width,
|
||||
drawer.top_row_height);
|
||||
|
||||
uiBlock *first_row_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
|
||||
|
||||
int left_x = drawer.left_column_width - scroll_offset_x;
|
||||
for (const int column_index : IndexRange(drawer.tot_columns)) {
|
||||
const int column_width = drawer.column_width(column_index);
|
||||
const int right_x = left_x + column_width;
|
||||
|
||||
CellDrawParams params;
|
||||
params.block = first_row_block;
|
||||
params.xmin = left_x;
|
||||
params.ymin = region->winy - drawer.top_row_height;
|
||||
params.width = column_width;
|
||||
params.height = drawer.top_row_height;
|
||||
drawer.draw_top_row_cell(column_index, params);
|
||||
|
||||
left_x = right_x;
|
||||
}
|
||||
|
||||
UI_block_end(C, first_row_block);
|
||||
UI_block_draw(C, first_row_block);
|
||||
|
||||
GPU_scissor_test(false);
|
||||
}
|
||||
|
||||
static void draw_cell_contents(const bContext *C,
|
||||
ARegion *region,
|
||||
const SpreadsheetDrawer &drawer,
|
||||
const int scroll_offset_x,
|
||||
const int scroll_offset_y)
|
||||
{
|
||||
GPU_scissor_test(true);
|
||||
GPU_scissor(drawer.left_column_width + 1,
|
||||
0,
|
||||
region->winx - drawer.left_column_width,
|
||||
region->winy - drawer.top_row_height);
|
||||
|
||||
uiBlock *cells_block = UI_block_begin(C, region, __func__, UI_EMBOSS_NONE);
|
||||
|
||||
int first_row, max_visible_rows;
|
||||
get_visible_rows(drawer, region, scroll_offset_y, &first_row, &max_visible_rows);
|
||||
|
||||
int left_x = drawer.left_column_width - scroll_offset_x;
|
||||
for (const int column_index : IndexRange(drawer.tot_columns)) {
|
||||
const int column_width = drawer.column_width(column_index);
|
||||
const int right_x = left_x + column_width;
|
||||
|
||||
if (right_x >= drawer.left_column_width && left_x <= region->winx) {
|
||||
for (const int row_index : IndexRange(first_row, max_visible_rows)) {
|
||||
if (row_index >= drawer.tot_rows) {
|
||||
break;
|
||||
}
|
||||
|
||||
CellDrawParams params;
|
||||
params.block = cells_block;
|
||||
params.xmin = left_x;
|
||||
params.ymin = region->winy - drawer.top_row_height - (row_index + 1) * drawer.row_height -
|
||||
scroll_offset_y;
|
||||
params.width = column_width;
|
||||
params.height = drawer.row_height;
|
||||
drawer.draw_content_cell(row_index, column_index, params);
|
||||
}
|
||||
}
|
||||
|
||||
left_x = right_x;
|
||||
}
|
||||
|
||||
UI_block_end(C, cells_block);
|
||||
UI_block_draw(C, cells_block);
|
||||
|
||||
GPU_scissor_test(false);
|
||||
}
|
||||
|
||||
static void update_view2d_tot_rect(const SpreadsheetDrawer &drawer,
|
||||
ARegion *region,
|
||||
const int row_amount)
|
||||
{
|
||||
int column_width_sum = 0;
|
||||
for (const int column_index : IndexRange(drawer.tot_columns)) {
|
||||
column_width_sum += drawer.column_width(column_index);
|
||||
}
|
||||
|
||||
UI_view2d_totRect_set(®ion->v2d,
|
||||
column_width_sum + drawer.left_column_width,
|
||||
row_amount * drawer.row_height + drawer.top_row_height);
|
||||
}
|
||||
|
||||
void draw_spreadsheet_in_region(const bContext *C,
|
||||
ARegion *region,
|
||||
const SpreadsheetDrawer &drawer)
|
||||
{
|
||||
UI_ThemeClearColor(TH_BACK);
|
||||
|
||||
View2D *v2d = ®ion->v2d;
|
||||
const int scroll_offset_y = v2d->cur.ymax;
|
||||
const int scroll_offset_x = v2d->cur.xmin;
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
|
||||
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
|
||||
|
||||
draw_index_column_background(pos, region, drawer);
|
||||
draw_alternating_row_overlay(pos, scroll_offset_y, region, drawer);
|
||||
draw_top_row_background(pos, region, drawer);
|
||||
draw_separator_lines(pos, scroll_offset_x, region, drawer);
|
||||
|
||||
immUnbindProgram();
|
||||
|
||||
draw_left_column_content(scroll_offset_y, C, region, drawer);
|
||||
draw_top_row_content(C, region, drawer, scroll_offset_x);
|
||||
draw_cell_contents(C, region, drawer, scroll_offset_x, scroll_offset_y);
|
||||
|
||||
update_view2d_tot_rect(drawer, region, drawer.tot_rows);
|
||||
|
||||
rcti scroller_mask;
|
||||
BLI_rcti_init(&scroller_mask,
|
||||
drawer.left_column_width,
|
||||
region->winx,
|
||||
0,
|
||||
region->winy - drawer.top_row_height);
|
||||
UI_view2d_scrollers_draw(v2d, &scroller_mask);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
60
source/blender/editors/space_spreadsheet/spreadsheet_draw.hh
Normal file
60
source/blender/editors/space_spreadsheet/spreadsheet_draw.hh
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 "BLI_vector.hh"
|
||||
|
||||
struct uiBlock;
|
||||
struct rcti;
|
||||
struct bContext;
|
||||
struct ARegion;
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
struct CellDrawParams {
|
||||
uiBlock *block;
|
||||
int xmin, ymin;
|
||||
int width, height;
|
||||
};
|
||||
|
||||
class SpreadsheetDrawer {
|
||||
public:
|
||||
int left_column_width;
|
||||
int top_row_height;
|
||||
int row_height;
|
||||
int tot_rows = 0;
|
||||
int tot_columns = 0;
|
||||
|
||||
SpreadsheetDrawer();
|
||||
virtual ~SpreadsheetDrawer();
|
||||
|
||||
virtual void draw_top_row_cell(int column_index, const CellDrawParams ¶ms) const;
|
||||
|
||||
virtual void draw_left_column_cell(int row_index, const CellDrawParams ¶ms) const;
|
||||
|
||||
virtual void draw_content_cell(int row_index,
|
||||
int column_index,
|
||||
const CellDrawParams ¶ms) const;
|
||||
|
||||
virtual int column_width(int column_index) const;
|
||||
};
|
||||
|
||||
void draw_spreadsheet_in_region(const bContext *C,
|
||||
ARegion *region,
|
||||
const SpreadsheetDrawer &spreadsheet_drawer);
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* 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 <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "BLF_api.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
#include "BKE_modifier.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
#include "spreadsheet_from_geometry.hh"
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
using blender::bke::ReadAttribute;
|
||||
using blender::bke::ReadAttributePtr;
|
||||
|
||||
class AttributeColumn {
|
||||
public:
|
||||
std::string name;
|
||||
int width;
|
||||
|
||||
AttributeColumn(std::string column_name) : name(std::move(column_name))
|
||||
{
|
||||
/* Compute the column width based on its name. */
|
||||
const int fontid = UI_style_get()->widget.uifont_id;
|
||||
const int header_name_padding = UI_UNIT_X;
|
||||
const int minimum_column_width = 3 * UI_UNIT_X;
|
||||
const int text_width = BLF_width(fontid, name.data(), name.size());
|
||||
width = std::max(text_width + header_name_padding, minimum_column_width);
|
||||
}
|
||||
|
||||
virtual ~AttributeColumn() = default;
|
||||
virtual void draw(const int index, const CellDrawParams ¶ms) const = 0;
|
||||
};
|
||||
|
||||
class GeometryAttributeSpreadsheetDrawer : public SpreadsheetDrawer {
|
||||
private:
|
||||
/* Contains resources that are used during drawing. They will be freed automatically. */
|
||||
std::unique_ptr<ResourceCollector> resources_;
|
||||
/* Information about how to draw the individual columns. */
|
||||
Vector<std::unique_ptr<AttributeColumn>> columns_;
|
||||
/* This is used to filter the selected rows. The referenced data lives at least as long as the
|
||||
* resource collector above. */
|
||||
Span<int64_t> visible_rows_;
|
||||
|
||||
public:
|
||||
GeometryAttributeSpreadsheetDrawer(std::unique_ptr<ResourceCollector> resources,
|
||||
Vector<std::unique_ptr<AttributeColumn>> columns,
|
||||
Span<int64_t> visible_rows,
|
||||
const int domain_size)
|
||||
: resources_(std::move(resources)), columns_(std::move(columns)), visible_rows_(visible_rows)
|
||||
{
|
||||
tot_columns = columns_.size();
|
||||
tot_rows = visible_rows.size();
|
||||
|
||||
/* Compute index column width based on number of digits. */
|
||||
const int fontid = UI_style_get()->widget.uifont_id;
|
||||
left_column_width = std::to_string(std::max(domain_size - 1, 0)).size() *
|
||||
BLF_width(fontid, "0", 1) +
|
||||
UI_UNIT_X * 0.75;
|
||||
}
|
||||
|
||||
void draw_top_row_cell(int column_index, const CellDrawParams ¶ms) const final
|
||||
{
|
||||
uiBut *but = uiDefIconTextBut(params.block,
|
||||
UI_BTYPE_LABEL,
|
||||
0,
|
||||
ICON_NONE,
|
||||
columns_[column_index]->name.c_str(),
|
||||
params.xmin,
|
||||
params.ymin,
|
||||
params.width,
|
||||
params.height,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
nullptr);
|
||||
/* Center-align column headers. */
|
||||
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
|
||||
UI_but_drawflag_disable(but, UI_BUT_TEXT_RIGHT);
|
||||
}
|
||||
|
||||
void draw_left_column_cell(int row_index, const CellDrawParams ¶ms) const final
|
||||
{
|
||||
const int real_index = visible_rows_[row_index];
|
||||
std::string index_str = std::to_string(real_index);
|
||||
uiBut *but = uiDefIconTextBut(params.block,
|
||||
UI_BTYPE_LABEL,
|
||||
0,
|
||||
ICON_NONE,
|
||||
index_str.c_str(),
|
||||
params.xmin,
|
||||
params.ymin,
|
||||
params.width,
|
||||
params.height,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
nullptr);
|
||||
/* Right-align indices. */
|
||||
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
|
||||
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
|
||||
}
|
||||
|
||||
void draw_content_cell(int row_index, int column_index, const CellDrawParams ¶ms) const final
|
||||
{
|
||||
const int real_index = visible_rows_[row_index];
|
||||
columns_[column_index]->draw(real_index, params);
|
||||
}
|
||||
|
||||
int column_width(int column_index) const final
|
||||
{
|
||||
return columns_[column_index]->width;
|
||||
}
|
||||
};
|
||||
|
||||
/* Utility to make writing column drawing code more concise. */
|
||||
template<typename DrawF> class CustomAttributeColumn : public AttributeColumn {
|
||||
private:
|
||||
DrawF draw_;
|
||||
|
||||
public:
|
||||
CustomAttributeColumn(std::string attribute_name, DrawF draw)
|
||||
: AttributeColumn(std::move(attribute_name)), draw_(std::move(draw))
|
||||
{
|
||||
}
|
||||
|
||||
void draw(const int index, const CellDrawParams ¶ms) const final
|
||||
{
|
||||
draw_(index, params);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DrawF>
|
||||
std::unique_ptr<CustomAttributeColumn<DrawF>> create_attribute_column(std::string attribute_name,
|
||||
DrawF draw)
|
||||
{
|
||||
return std::make_unique<CustomAttributeColumn<DrawF>>(std::move(attribute_name),
|
||||
std::move(draw));
|
||||
}
|
||||
|
||||
static Vector<std::string> get_sorted_attribute_names_to_display(
|
||||
const GeometryComponent &component, const AttributeDomain domain)
|
||||
{
|
||||
Vector<std::string> attribute_names;
|
||||
component.attribute_foreach(
|
||||
[&](const StringRef attribute_name, const AttributeMetaData &meta_data) {
|
||||
if (meta_data.domain == domain) {
|
||||
attribute_names.append(attribute_name);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
std::sort(attribute_names.begin(),
|
||||
attribute_names.end(),
|
||||
[](const std::string &a, const std::string &b) {
|
||||
return BLI_strcasecmp_natural(a.c_str(), b.c_str()) < 0;
|
||||
});
|
||||
return attribute_names;
|
||||
}
|
||||
|
||||
static void draw_float_in_cell(const CellDrawParams ¶ms, const float value)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(3) << value;
|
||||
const std::string value_str = ss.str();
|
||||
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);
|
||||
}
|
||||
|
||||
static void draw_int_in_cell(const CellDrawParams ¶ms, const int value)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static void draw_bool_in_cell(const CellDrawParams ¶ms, const bool value)
|
||||
{
|
||||
const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT;
|
||||
uiDefIconTextBut(params.block,
|
||||
UI_BTYPE_LABEL,
|
||||
0,
|
||||
icon,
|
||||
"",
|
||||
params.xmin,
|
||||
params.ymin,
|
||||
params.width,
|
||||
params.height,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
static void add_columns_for_attribute(const ReadAttribute *attribute,
|
||||
const StringRefNull attribute_name,
|
||||
Vector<std::unique_ptr<AttributeColumn>> &columns)
|
||||
{
|
||||
const CustomDataType data_type = attribute->custom_data_type();
|
||||
switch (data_type) {
|
||||
case CD_PROP_FLOAT: {
|
||||
columns.append(create_attribute_column(attribute_name,
|
||||
[attribute](int index, const CellDrawParams ¶ms) {
|
||||
float value;
|
||||
attribute->get(index, &value);
|
||||
draw_float_in_cell(params, value);
|
||||
}));
|
||||
break;
|
||||
}
|
||||
case CD_PROP_FLOAT2: {
|
||||
static std::array<char, 2> axis_char = {'X', 'Y'};
|
||||
for (const int i : {0, 1}) {
|
||||
std::string name = attribute_name + " " + axis_char[i];
|
||||
columns.append(
|
||||
create_attribute_column(name, [attribute, i](int index, const CellDrawParams ¶ms) {
|
||||
float2 value;
|
||||
attribute->get(index, &value);
|
||||
draw_float_in_cell(params, value[i]);
|
||||
}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CD_PROP_FLOAT3: {
|
||||
static std::array<char, 3> axis_char = {'X', 'Y', 'Z'};
|
||||
for (const int i : {0, 1, 2}) {
|
||||
std::string name = attribute_name + " " + axis_char[i];
|
||||
columns.append(
|
||||
create_attribute_column(name, [attribute, i](int index, const CellDrawParams ¶ms) {
|
||||
float3 value;
|
||||
attribute->get(index, &value);
|
||||
draw_float_in_cell(params, value[i]);
|
||||
}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CD_PROP_COLOR: {
|
||||
static std::array<char, 4> axis_char = {'R', 'G', 'B', 'A'};
|
||||
for (const int i : {0, 1, 2, 3}) {
|
||||
std::string name = attribute_name + " " + axis_char[i];
|
||||
columns.append(
|
||||
create_attribute_column(name, [attribute, i](int index, const CellDrawParams ¶ms) {
|
||||
Color4f value;
|
||||
attribute->get(index, &value);
|
||||
draw_float_in_cell(params, value[i]);
|
||||
}));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CD_PROP_INT32: {
|
||||
columns.append(create_attribute_column(attribute_name,
|
||||
[attribute](int index, const CellDrawParams ¶ms) {
|
||||
int value;
|
||||
attribute->get(index, &value);
|
||||
draw_int_in_cell(params, value);
|
||||
}));
|
||||
break;
|
||||
}
|
||||
case CD_PROP_BOOL: {
|
||||
columns.append(create_attribute_column(attribute_name,
|
||||
[attribute](int index, const CellDrawParams ¶ms) {
|
||||
bool value;
|
||||
attribute->get(index, &value);
|
||||
draw_bool_in_cell(params, value);
|
||||
}));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GeometrySet get_display_geometry_set(Object *object_eval)
|
||||
{
|
||||
GeometrySet geometry_set;
|
||||
if (object_eval->mode == OB_MODE_EDIT) {
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
|
||||
if (mesh == nullptr) {
|
||||
return geometry_set;
|
||||
}
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
|
||||
mesh_component.copy_vertex_group_names_from_object(*object_eval);
|
||||
}
|
||||
else {
|
||||
if (object_eval->runtime.geometry_set_eval != nullptr) {
|
||||
/* This does not copy the geometry data itself. */
|
||||
geometry_set = *object_eval->runtime.geometry_set_eval;
|
||||
}
|
||||
}
|
||||
return geometry_set;
|
||||
}
|
||||
|
||||
static Span<int64_t> filter_visible_mesh_vertex_rows(const bContext *C,
|
||||
Object *object_eval,
|
||||
const MeshComponent *component,
|
||||
ResourceCollector &resources)
|
||||
{
|
||||
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
|
||||
const bool show_only_selected = sspreadsheet->filter_flag & SPREADSHEET_FILTER_SELECTED_ONLY;
|
||||
if (object_eval->mode == OB_MODE_EDIT && show_only_selected) {
|
||||
Object *object_orig = DEG_get_original_object(object_eval);
|
||||
Vector<int64_t> &visible_rows = resources.construct<Vector<int64_t>>("visible rows");
|
||||
const Mesh *mesh_eval = component->get_for_read();
|
||||
Mesh *mesh_orig = (Mesh *)object_orig->data;
|
||||
BMesh *bm = mesh_orig->edit_mesh->bm;
|
||||
BM_mesh_elem_table_ensure(bm, BM_VERT);
|
||||
|
||||
int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
|
||||
if (orig_indices != nullptr) {
|
||||
/* Use CD_ORIGINDEX layer if it exists. */
|
||||
for (const int i_eval : IndexRange(mesh_eval->totvert)) {
|
||||
const int i_orig = orig_indices[i_eval];
|
||||
if (i_orig >= 0 && i_orig < bm->totvert) {
|
||||
BMVert *vert = bm->vtable[i_orig];
|
||||
if (BM_elem_flag_test(vert, BM_ELEM_SELECT)) {
|
||||
visible_rows.append(i_eval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mesh_eval->totvert == bm->totvert) {
|
||||
/* Use a simple heuristic to match original vertices to evaluated ones. */
|
||||
for (const int i : IndexRange(mesh_eval->totvert)) {
|
||||
BMVert *vert = bm->vtable[i];
|
||||
if (BM_elem_flag_test(vert, BM_ELEM_SELECT)) {
|
||||
visible_rows.append(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* This is safe, because the vector lives in the resource collector. */
|
||||
return visible_rows.as_span();
|
||||
}
|
||||
/* No filter is used. */
|
||||
const int domain_size = component->attribute_domain_size(ATTR_DOMAIN_POINT);
|
||||
return IndexRange(domain_size).as_span();
|
||||
}
|
||||
|
||||
std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_geometry_attributes(const bContext *C,
|
||||
Object *object_eval)
|
||||
{
|
||||
/* Create a resource collector that owns stuff that needs to live until drawing is done. */
|
||||
std::unique_ptr<ResourceCollector> resources = std::make_unique<ResourceCollector>();
|
||||
GeometrySet &geometry_set = resources->add_value(get_display_geometry_set(object_eval),
|
||||
"geometry set");
|
||||
|
||||
const AttributeDomain domain = ATTR_DOMAIN_POINT;
|
||||
const GeometryComponentType component_type = GeometryComponentType::Mesh;
|
||||
const GeometryComponent *component = geometry_set.get_component_for_read(component_type);
|
||||
if (component == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
Vector<std::string> attribute_names = get_sorted_attribute_names_to_display(*component, domain);
|
||||
|
||||
Vector<std::unique_ptr<AttributeColumn>> columns;
|
||||
for (StringRefNull attribute_name : attribute_names) {
|
||||
ReadAttributePtr attribute_ptr = component->attribute_try_get_for_read(attribute_name);
|
||||
ReadAttribute &attribute = *attribute_ptr;
|
||||
resources->add(std::move(attribute_ptr), "attribute");
|
||||
add_columns_for_attribute(&attribute, attribute_name, columns);
|
||||
}
|
||||
|
||||
/* The filter below only works for mesh vertices currently. */
|
||||
BLI_assert(domain == ATTR_DOMAIN_POINT && component_type == GeometryComponentType::Mesh);
|
||||
Span<int64_t> visible_rows = filter_visible_mesh_vertex_rows(
|
||||
C, object_eval, static_cast<const MeshComponent *>(component), *resources);
|
||||
|
||||
const int domain_size = component->attribute_domain_size(domain);
|
||||
return std::make_unique<GeometryAttributeSpreadsheetDrawer>(
|
||||
std::move(resources), std::move(columns), visible_rows, domain_size);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 "BKE_geometry_set.hh"
|
||||
|
||||
#include "BLI_resource_collector.hh"
|
||||
|
||||
#include "spreadsheet_draw.hh"
|
||||
|
||||
struct bContext;
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_geometry_attributes(
|
||||
const bContext *C, Object *object_eval);
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
@@ -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 ¶ms) 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 ¶ms) 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 ¶ms) 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 ¶ms, 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
|
@@ -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
|
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
void spreadsheet_operatortypes(void);
|
21
source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
Normal file
21
source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 "spreadsheet_intern.hh"
|
||||
|
||||
void spreadsheet_operatortypes()
|
||||
{
|
||||
}
|
@@ -1834,6 +1834,33 @@ typedef struct SpaceStatusBar {
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Spreadsheet
|
||||
* \{ */
|
||||
|
||||
typedef struct SpaceSpreadsheet {
|
||||
SpaceLink *next, *prev;
|
||||
/** Storage of regions for inactive spaces. */
|
||||
ListBase regionbase;
|
||||
char spacetype;
|
||||
char link_flag;
|
||||
char _pad0[6];
|
||||
/* End 'SpaceLink' header. */
|
||||
|
||||
struct ID *pinned_id;
|
||||
|
||||
/* eSpaceSpreadsheet_FilterFlag. */
|
||||
uint8_t filter_flag;
|
||||
|
||||
char _pad1[7];
|
||||
} SpaceSpreadsheet;
|
||||
|
||||
/** \} */
|
||||
|
||||
typedef enum eSpaceSpreadsheet_FilterFlag {
|
||||
SPREADSHEET_FILTER_SELECTED_ONLY = (1 << 0),
|
||||
} eSpaceSpreadsheet_FilterFlag;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Space Defines (eSpace_Type)
|
||||
* \{ */
|
||||
@@ -1871,8 +1898,9 @@ typedef enum eSpace_Type {
|
||||
SPACE_CLIP = 20,
|
||||
SPACE_TOPBAR = 21,
|
||||
SPACE_STATUSBAR = 22,
|
||||
SPACE_SPREADSHEET = 23
|
||||
|
||||
#define SPACE_TYPE_LAST SPACE_STATUSBAR
|
||||
#define SPACE_TYPE_LAST SPACE_SPREADSHEET
|
||||
} eSpace_Type;
|
||||
|
||||
/* use for function args */
|
||||
|
@@ -492,6 +492,7 @@ typedef struct bTheme {
|
||||
ThemeSpace space_clip;
|
||||
ThemeSpace space_topbar;
|
||||
ThemeSpace space_statusbar;
|
||||
ThemeSpace space_spreadsheet;
|
||||
|
||||
/* 20 sets of bone colors for this theme */
|
||||
ThemeWireColor tarm[20];
|
||||
@@ -507,7 +508,7 @@ typedef struct bTheme {
|
||||
#define UI_THEMESPACE_START(btheme) \
|
||||
(CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->space_properties))
|
||||
#define UI_THEMESPACE_END(btheme) \
|
||||
(CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_statusbar) + 1))
|
||||
(CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_spreadsheet) + 1))
|
||||
|
||||
typedef struct bAddon {
|
||||
struct bAddon *next, *prev;
|
||||
|
@@ -601,6 +601,7 @@ extern StructRNA RNA_SpaceOutliner;
|
||||
extern StructRNA RNA_SpacePreferences;
|
||||
extern StructRNA RNA_SpaceProperties;
|
||||
extern StructRNA RNA_SpaceSequenceEditor;
|
||||
extern StructRNA RNA_SpaceSpreadsheet;
|
||||
extern StructRNA RNA_SpaceTextEditor;
|
||||
extern StructRNA RNA_SpaceUVEditor;
|
||||
extern StructRNA RNA_SpaceView3D;
|
||||
|
@@ -145,6 +145,11 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
|
||||
"Properties",
|
||||
"Edit properties of active object and related data-blocks"},
|
||||
{SPACE_FILE, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", "Browse for files and assets"},
|
||||
{SPACE_SPREADSHEET,
|
||||
"SPREADSHEET",
|
||||
ICON_SPREADSHEET,
|
||||
"Spreadsheet",
|
||||
"Explore geometry data in a table"},
|
||||
{SPACE_USERPREF,
|
||||
"PREFERENCES",
|
||||
ICON_PREFERENCES,
|
||||
@@ -571,6 +576,8 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
|
||||
return &RNA_SpacePreferences;
|
||||
case SPACE_CLIP:
|
||||
return &RNA_SpaceClipEditor;
|
||||
case SPACE_SPREADSHEET:
|
||||
return &RNA_SpaceSpreadsheet;
|
||||
|
||||
/* Currently no type info. */
|
||||
case SPACE_SCRIPT:
|
||||
@@ -2976,6 +2983,14 @@ static void rna_SpaceFileBrowser_browse_mode_update(Main *UNUSED(bmain),
|
||||
ED_area_tag_refresh(area);
|
||||
}
|
||||
|
||||
static void rna_SpaceSpreadsheet_pinned_id_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
struct ReportList *UNUSED(reports))
|
||||
{
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
|
||||
sspreadsheet->pinned_id = value.data;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static const EnumPropertyItem dt_uv_items[] = {
|
||||
@@ -7169,6 +7184,27 @@ static void rna_def_space_clip(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_space_spreadsheet(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space");
|
||||
RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data");
|
||||
|
||||
prop = RNA_def_property(srna, "pinned_id", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceSpreadsheet_pinned_id_set", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "Pinned ID", "Data-block whose values are displayed");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_SELECTED_ONLY);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Show Only Selected", "Only include rows that correspond to selected elements");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
|
||||
}
|
||||
|
||||
void RNA_def_space(BlenderRNA *brna)
|
||||
{
|
||||
rna_def_space(brna);
|
||||
@@ -7194,6 +7230,7 @@ void RNA_def_space(BlenderRNA *brna)
|
||||
rna_def_node_tree_path(brna);
|
||||
rna_def_space_node(brna);
|
||||
rna_def_space_clip(brna);
|
||||
rna_def_space_spreadsheet(brna);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -3847,6 +3847,26 @@ static void rna_def_userdef_theme_space_statusbar(BlenderRNA *brna)
|
||||
rna_def_userdef_theme_spaces_main(srna);
|
||||
}
|
||||
|
||||
static void rna_def_userdef_theme_space_spreadsheet(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* space_spreadsheet */
|
||||
|
||||
srna = RNA_def_struct(brna, "ThemeSpreadsheet", NULL);
|
||||
RNA_def_struct_sdna(srna, "ThemeSpace");
|
||||
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
|
||||
RNA_def_struct_ui_text(srna, "Theme Spreadsheet", "Theme settings for the Spreadsheet");
|
||||
|
||||
prop = RNA_def_property(srna, "row_alternate", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_array(prop, 4);
|
||||
RNA_def_property_ui_text(prop, "Alternate Rows", "Overlay color on every other row");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
|
||||
|
||||
rna_def_userdef_theme_spaces_main(srna);
|
||||
}
|
||||
|
||||
static void rna_def_userdef_themes(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
@@ -3873,6 +3893,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
|
||||
{20, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", ""},
|
||||
{21, "TOPBAR", ICON_TOPBAR, "Top Bar", ""},
|
||||
{22, "STATUSBAR", ICON_STATUSBAR, "Status Bar", ""},
|
||||
{23, "SPREADSHEET", ICON_SPREADSHEET, "Spreadsheet"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -4001,6 +4022,12 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "space_statusbar");
|
||||
RNA_def_property_struct_type(prop, "ThemeStatusBar");
|
||||
RNA_def_property_ui_text(prop, "Status Bar", "");
|
||||
|
||||
prop = RNA_def_property(srna, "spreadsheet", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "space_spreadsheet");
|
||||
RNA_def_property_struct_type(prop, "ThemeSpreadsheet");
|
||||
RNA_def_property_ui_text(prop, "Spreadsheet", "");
|
||||
/* end space types */
|
||||
|
||||
prop = RNA_def_property(srna, "bone_color_sets", PROP_COLLECTION, PROP_NONE);
|
||||
@@ -4254,6 +4281,7 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna)
|
||||
rna_def_userdef_theme_space_clip(brna);
|
||||
rna_def_userdef_theme_space_topbar(brna);
|
||||
rna_def_userdef_theme_space_statusbar(brna);
|
||||
rna_def_userdef_theme_space_spreadsheet(brna);
|
||||
rna_def_userdef_theme_colorset(brna);
|
||||
rna_def_userdef_theme_collection_color(brna);
|
||||
rna_def_userdef_themes(brna);
|
||||
|
@@ -427,6 +427,7 @@ typedef struct wmNotifier {
|
||||
#define ND_SPACE_CHANGED (19 << 16) /*sent to a new editor type after it's replaced an old one*/
|
||||
#define ND_SPACE_CLIP (20 << 16)
|
||||
#define ND_SPACE_FILE_PREVIEW (21 << 16)
|
||||
#define ND_SPACE_SPREADSHEET (22 << 16)
|
||||
|
||||
/* subtype, 256 entries too */
|
||||
#define NOTE_SUBTYPE 0x0000FF00
|
||||
|
Reference in New Issue
Block a user