1
1

Compare commits

...

66 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
381e2d4dc2 Merge branch 'master' into temp-spreadsheet-editor 2021-03-05 10:22:39 +01:00
cf6208382e Merge branch 'master' into temp-spreadsheet-editor 2021-03-03 12:36:51 +01:00
b837933b17 Cleanup: clang-tidy 2021-03-03 12:36:48 +01:00
3ca094651b cleanup 2021-03-02 12:00:25 +01:00
ad8238cb51 improve comment 2021-03-02 11:55:59 +01:00
9c58324b78 make naming more consistent 2021-03-02 11:55:14 +01:00
f78dd85077 update editor on mode change 2021-03-02 11:49:55 +01:00
8ce62fedd8 make title row a bit thinner 2021-03-02 11:49:15 +01:00
fba3d696ee fix ensure bmesh table 2021-03-02 11:18:42 +01:00
ea0bfde339 Merge branch 'master' into temp-spreadsheet-editor 2021-03-02 10:57:27 +01:00
7ab29c748a header listeners 2021-03-01 18:18:14 +01:00
be36c4d37d initial listeners for main region 2021-03-01 16:59:04 +01:00
c5bf114d78 add theme for spreadsheet editor 2021-03-01 16:10:29 +01:00
51c844d69b cleanup includes 2021-03-01 15:46:01 +01:00
e0ef38f3ac Spreadsheet: New spreadsheet editor (WIP).
Differential Revision: https://developer.blender.org/D10566
2021-03-01 13:49:18 +01:00
8451fa3125 Merge branch 'master' into temp-spreadsheet-editor 2021-03-01 10:29:34 +01:00
c0b8a767b4 enable view2d buttons keymap
This mainly activates the page up/down keys.
2021-02-26 16:48:33 +01:00
cb8dd9905a initial support for rows for selected vertices 2021-02-26 16:23:43 +01:00
4df7e6047b use new spreadsheet icon 2021-02-26 11:44:57 +01:00
b2774b03b9 Merge branch 'master' into temp-spreadsheet-editor 2021-02-26 11:39:31 +01:00
81d4e4d35e split spreadsheet editor code into multiple files 2021-02-25 17:20:49 +01:00
1e6d38133e Merge branch 'master' into temp-spreadsheet-editor 2021-02-25 17:18:22 +01:00
6e261f79ef Merge branch 'master' into temp-spreadsheet-editor 2021-02-25 16:58:46 +01:00
a977ed1920 automatically adapt index column width 2021-02-25 13:30:35 +01:00
83ed51c2f1 automatically adapt column width 2021-02-25 13:24:11 +01:00
fa62b24b57 draw float2 attributes 2021-02-25 13:09:36 +01:00
18d99cd5fb draw bool attributes 2021-02-25 13:06:33 +01:00
cc3e6c4950 don't draw invisible column cells 2021-02-25 12:57:51 +01:00
5a71c3cb56 draw color attributes 2021-02-25 12:54:20 +01:00
e2cf5b8b2e draw integer attributes 2021-02-25 12:50:20 +01:00
e67275538a show float and float3 attributes 2021-02-25 12:40:24 +01:00
179dfdccd2 draw attribute name 2021-02-25 12:04:23 +01:00
17615ab5aa initial pinning in header ui 2021-02-25 11:14:13 +01:00
1b34d6cd79 Merge branch 'master' into temp-spreadsheet-editor 2021-02-25 10:00:37 +01:00
e7e3f17c49 Merge branch 'master' into temp-spreadsheet-editor 2021-02-24 18:43:18 +01:00
10804043a5 fixes 2021-02-24 18:12:48 +01:00
b79cd1cb03 refactor spreadsheet drawing 2021-02-24 18:06:04 +01:00
7f9f6ac29f Merge branch 'master' into temp-spreadsheet-editor 2021-02-24 18:05:25 +01:00
d829a0a607 include gpu 2021-02-24 13:02:15 +01:00
a0191eb889 Merge branch 'master' into temp-spreadsheet-editor 2021-02-24 12:15:04 +01:00
1868880e7a enable scrollbars 2021-02-23 17:07:12 +01:00
247707c52a cleanup 2021-02-23 17:07:02 +01:00
64ddb1c8f2 right align indices 2021-02-23 17:03:22 +01:00
70b0b63d7b draw float attributes 2021-02-23 16:57:56 +01:00
c4b67853bd save spreadsheet space in file 2021-02-23 16:38:04 +01:00
67c2ef5242 Merge branch 'master' into temp-spreadsheet-editor 2021-02-23 15:36:06 +01:00
8568bed752 write attribute names and row indices 2021-02-23 13:18:25 +01:00
0ad34e603c Merge branch 'master' into temp-spreadsheet-editor 2021-02-23 11:53:35 +01:00
2e8d77967e hookup view2d to spreadsheet editor 2021-02-23 11:41:36 +01:00
525819b1af Merge branch 'master' into temp-spreadsheet-editor 2021-02-23 10:52:02 +01:00
eb6b26192d cleanup 2021-02-22 16:55:52 +01:00
27373011de initial drawing into block directly 2021-02-22 16:13:37 +01:00
ced130f849 register basic listener 2021-02-22 14:01:34 +01:00
6ff897157c draw vertex positions 2021-02-22 13:45:29 +01:00
73872fd0e0 initial drawing 2021-02-22 13:11:47 +01:00
794c0a09eb spreadsheet background 2021-02-22 12:53:30 +01:00
886d28f342 initial header drawing 2021-02-22 12:47:26 +01:00
6989349251 remove warnings 2021-02-22 12:39:22 +01:00
eedc06b6b2 actually create spreadsheet 2021-02-22 11:22:31 +01:00
ea58786120 initial spreadsheet boilerplate code 2021-02-22 11:12:23 +01:00
33 changed files with 1739 additions and 2 deletions

View File

@@ -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),

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

@@ -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"

View File

@@ -45,6 +45,7 @@ _modules = [
"rigidbody",
"screen_play_rendered_anim",
"sequencer",
"spreadsheet",
"userpref",
"uvcalc_follow_active",
"uvcalc_lightmap",

View 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,
)

View File

@@ -86,6 +86,7 @@ _modules = [
"space_outliner",
"space_properties",
"space_sequencer",
"space_spreadsheet",
"space_statusbar",
"space_text",
"space_time",

View 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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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++) {

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View 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}")

View 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(&region->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(&region->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);
}

View 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(&region->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 = &region->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

View 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 &params) const;
virtual void draw_left_column_cell(int row_index, const CellDrawParams &params) const;
virtual void draw_content_cell(int row_index,
int column_index,
const CellDrawParams &params) 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

View File

@@ -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 &params) 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 &params) 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 &params) 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 &params) 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 &params) 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 &params, 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 &params, 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 &params, 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 &params) {
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 &params) {
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 &params) {
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 &params) {
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 &params) {
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 &params) {
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

View File

@@ -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

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

View File

@@ -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);

View 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()
{
}

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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