1
1

Compare commits

...

101 Commits

Author SHA1 Message Date
c7904d2398 Merge branch 'master' into ui-asset-view-template 2021-03-31 22:53:03 +02:00
91b87d8d7f Cleanup: Improve naming of new temporary ID consumer functions 2021-03-25 19:10:11 +01:00
e7462cfa44 Asset Browser: correct the declared context keys
The file browser context (when in asset browser mode) was declaring the
wrong context keys, making it impossible to use `context.copy()` in Python.
2021-03-25 19:03:13 +01:00
2c65710c9a Merge branch 'master' into ui-asset-view-template 2021-03-24 14:35:45 +01:00
01a5d3fa28 Support passing operator to invoke on activating or dragging an item
An annoyance is that the operator names have to be passed to the template which
makes the already long argument list even longer.
Thought about a couple of ways to do this, unfortunately this is the only
decent way to do this that I see. There's also no way to pass operator options
currently.

Getting the handling to work correctly took some effort, and the code is not
exactly nice.

Note that even though we activate the item when calling the custom drag
operator (helps indicating the pose being blended for example), we only call
the drag operator then, not the activate one. They are never executed both.

Also note that this won't compile right now, I'll have to commit some changes
to master first.
2021-03-24 13:54:33 +01:00
10383566b8 Add utilities to temporarily append asset IDs
Uses the new `BLO_library_temp_xxx` functions, but deals with all the asset
specific file path building. This is a reasonable utility for the asset system
to have, it will probably be needed by more asset types than IDs.
2021-03-24 13:34:16 +01:00
c6182a91c3 Require identifier for asset view template usages
Needed if we want to support multiple different asset views in future.
2021-03-24 13:25:45 +01:00
5a94ab9ac2 Allow getting asset library and active asset handle via context
`CTX_wm_asset_library()` returns the active asset library from the workspace,
or the the Asset Browser one while inside that. The active asset handle is set
by the Asset Browser and the asset view UI template so that operators executed
via the template can access it.
2021-03-24 13:25:09 +01:00
fd6015f9fd Merge branch 'master' into ui-asset-view-template 2021-03-24 12:22:57 +01:00
12d7b71294 Fix crash when showing empty shape-keys list 2021-03-21 16:46:36 +01:00
552fec44da Geometry Nodes: Make cone primitive 2m tall by default
This gives the cone mesh primitive more pleasing proportions by default.
2021-03-21 16:11:38 +01:00
269dc0bbc6 Geometry Nodes: Move cone primtive to rest on its base by default
This is generally what people expect when generating a cone. Note that
this translation currently happens after the rotation, but since the rotation
will likely be removed in the future, that won't be a problem for long.
2021-03-21 16:11:38 +01:00
c81ac61e58 Geometry Nodes: Implicit interpolations to and from the edge domain
This patch adds the remaining 6 interpolations for mesh domains.
The new interpolations are:
 - Corner / point / polygon to edge
 - Edge to corner / point / polygon

After this it is possible to adapt an attribute to and from every
mesh domain. This is simple to test with the "Attribute Convert" node.

Though, as a note for the future, there are still some improvements
possible to the interpolations, like lazily calculating values for the
interpolations where it's possible, and slightly improving the
algorithms used for some interpolations, like using corner angles
for polygon to point.

Differential Revision: https://developer.blender.org/D10765
2021-03-21 16:11:38 +01:00
eecaca8b2a Fix Cycles NaN assert in random walk SSS due to very small throughput
Now terminate if there are many bounces and the throughput gets so small
that we get precision issues.
2021-03-21 16:11:38 +01:00
c56e8ae919 LibOverride: fix code trying to auto-resync linked overrides.
This is not only potentially extremely expensive, it is also fairly
futile, and code is not designed to handle it currently anyway (could
easily end up in inifinite loops and other crashes).
2021-03-21 16:11:38 +01:00
Angus Stanton
c8b925cafb Fix T86208: copy node group button is inconsistent in geometry nodes
Differential Revision: https://developer.blender.org/D10740
2021-03-21 16:11:38 +01:00
064a379205 Cleanup: add const. 2021-03-21 16:11:38 +01:00
545bbcc7f3 Cleanup: Replace std::vector with blender::Vector. 2021-03-21 16:11:38 +01:00
84060a0eb1 Fix T86710: Crash When Adding Node Group.
When adding a node group there can be no inputs in the input map that
was triggering an assert.
2021-03-21 16:11:38 +01:00
59f7044134 Cleanup: remove unused function 2021-03-21 16:11:38 +01:00
fac59931c7 Cleanup: minor changes to pose-mode apply visual transform
- Remove use of evaluated poses, instead calculate transformations
  into an array which is applied afterwards.

- Only update ID's for poses that have been changed.
2021-03-21 16:11:38 +01:00
aae7ea2874 BLI: Add location, rotation, scale constructor to float4x4
This is simply a convenience when using this type. More similar
constructors can be added in the future when they are useful.

Differential Revision: https://developer.blender.org/D10714
2021-03-21 16:11:38 +01:00
Patrick Busch
1bd3645deb Python API: Expose CurveProfile Reset View function
Allow python access to the `reset_view` functionality which before
was only available through the menu. This was suggested for
consistency after D10561.

Differential Revision: https://developer.blender.org/D10595
2021-03-21 16:11:38 +01:00
Pratik Borhade
a4a6c2a1a4 Fix T86701: Geometry nodes Cube and UV Sphere mesh size
The size in the transform matrices was extra, since it is also
passed as an argument to the BMesh operators.

Differential Revision: https://developer.blender.org/D10763
2021-03-21 16:11:37 +01:00
2199796694 Geometry Nodes: Don't create empty components when realizing instances
Previously even if the input goemetry set had no point cloud or no mesh
instances, `geometry_set_realize_instances` would create empty data.
This isn't necessarily bad, but it can complicate things down the line if
there are a bunch of empty components getting passed around.
2021-03-21 16:11:37 +01:00
a9613b2947 Fix T86448 EEVEE: SSRefraction Depth regression
Caused by recent change for contact shadow raytracing. rB4e236326c137
2021-03-21 16:11:37 +01:00
392a1d8a9f GPencil: Rename Options panel to Settings
This change is to keep consistency with other panels with the same functionality.

Reviewed by @pablovazquez
2021-03-21 16:11:37 +01:00
3b28a68d97 Fix T86677: select grouped in node editor crashes without active node
This was reported for geometry nodes, but was true for all nodetrees
(e.g. after deleting the active node). Geometry node trees just made
this more obvious since they start without an active node to begin with.

Fix provided by @lone_noel, thx!

Maniphest Tasks: T86677

Differential Revision: https://developer.blender.org/D10762
2021-03-21 16:11:37 +01:00
c0cf72a6fd Fix T86548: Sculpt: Mask by Color tool not working
Caused by {rB2917f550caa9} which renamed the entry in the toolsystem,
but not the corresponding keymap.

Maniphest Tasks: T86548

Differential Revision: https://developer.blender.org/D10725
2021-03-21 16:11:37 +01:00
bb95895b19 LibOverride: Fix missing update after an override reset.
We need to brute-force reset IDs with `ID_RECALC_ALL` here...
2021-03-21 16:11:37 +01:00
412d760efa LibOverride: Outliner: Rename Add... to Make....
Also more consistent with the name used for the 3DView operator.
2021-03-21 16:11:37 +01:00
c8cb79e309 Fix 3DView not updating on some NC_ID notifiers.
Outliner uses a lot `NC_ID | NA_EDITED` e.g., which was not caught by
the View3D editor for update.
2021-03-21 16:11:37 +01:00
afb2974c34 LibOverride: Outliner: Tweak override creation from instancing empty.
Now behavior is similar to the one from 3DView: once override of the
collection is successfuly created, we remove the instancing empty from
the scene.
2021-03-21 16:11:37 +01:00
dfaf420e93 Fix missing view3d updates after recent NC_SPACE notifier filters
Since {rB46aa70cb486d}, using `NC_SPACE | ND_SPACE_VIEW3D` as notifier is
restricted to space data as a reference. This was still used though for
RNA updates in other places (namely `rna_camera`, `rna_scene`,
`rna_animviz`), and passing NULL would automatically set the notifier
reference to the owner id. Above commit would happily filter these out,
leading to missing refreshes.

Now use more specific notifiers (in case of animviz a new
`ND_DRAW_ANIMVIZ` was added).

This was reported for Camera background images btw.
Fixes T86670.

Maniphest Tasks: T86670

Differential Revision: https://developer.blender.org/D10758
2021-03-21 16:11:37 +01:00
c026bb2961 Cleanup: Python code style 2021-03-19 17:14:54 +01:00
063c248cb7 Fix race condition when multiple file/asset-lists are running at once
E.g. opening a file with an asset viewer and an Asset Browser could cause one
of them to not load its files properly. That is because there was only one
`wmJob` per scene so when the first one was done it would end the other one(s).
I think this would be a problem in master for the regular File Browser too.

Instead of setting the scene as owner of the job, use the file-list, so that
each file/asset-list gets its own job.
2021-03-19 17:09:43 +01:00
40ed613609 Cleanup: First round of polishing (C++ style, type safety, naming, etc)
* Follow "rule of five"
* Explicit conversion constructors
* Separate inteface declarations from definitions (readability)
* Avoid clang-tidy error
* Naming
....
2021-03-18 19:47:09 +01:00
d78754ff18 Merge branch 'master' into ui-asset-view-template 2021-03-18 15:30:35 +01:00
02ccd5931a Use custom collection property to pass the asset list to UI lists
`UIList` is designed to use collection properties. I previously did a
whole bunch of hacks to use it without. This isn't acceptable for
master, instead a proper collection property should be provided.

Idea is to let scripts register a custom collection property, that the
asset view template can fill with the latest asset list contents and
pass that to the UI list.

Longer term I'd prefer if the UI code would support other containers,
and not rely so much on RNA and custom/ID properties. I have ideas and
plans for this, but meanwhile, this will do to remove the hacks.
2021-03-17 20:51:03 +01:00
b485710a25 Fix warning about possibly mixed C/C++ linkage of type
Would give a warning:
```
'ED_asset_library_reference_from_enum_value' has C-linkage specified, but
returns incomplete type 'struct AssetLibraryReference' which could be
incompatible with C [-Wreturn-type-c-linkage]
```
2021-03-17 13:56:20 +01:00
9b2661a8e0 Construct-on-first-use to stay far away from static init. fiasco
We didn't actually run into the static initialization fiasco, but only
because `blender::Map` didn't use the guarded allocator on default
destruction. Better to stay far way from static initialization fiasco,
and the construct on first use idiom is trivial and prevents it. So
better use that.
2021-03-16 17:38:00 +01:00
19e1ae866f Fix asset storage crash when closing Blender in release mode 2021-03-16 16:44:12 +01:00
96543946b2 Use custom .py property for active asset index, stored in the workspace
Previously I just used the active color index of the first palette to
get things to work.
I would've preferred if the asset view template could register own
properties and store them in the `UIList` it creates. That way you could
have multiple asset views with entirely independent data. But since this
isn't possible, we need a different way to store such data, I think the
workspace makes sense. It should still be possible to store different
data for different use-cases, e.g. to show a pose asset list in pose
mode and a material asset list in object mode. So idea is to let
scripts/add-ons register custom properties for their specific use case
(e.g. "Active Pose Asset" for the pose libraries).
2021-03-16 15:43:48 +01:00
0e071e015e Store active asset library at workspace level
The Asset Browser still has its own active asset library. But for the UI
(e.g. the asset view UI template), there is one active asset library per
workspace now. This is needed because for technical reasons the property
has to be registered in C, ideally you could just register it as custom
property for any use-case and pass that to the asset view template.
Since this isn't possible, an active asset library per workspace seems
reasonable.
2021-03-16 13:06:50 +01:00
2fad30ba1e Merge branch 'master' into ui-asset-view-template 2021-03-16 11:43:51 +01:00
3d706bb0f3 Do proper updates when local asset data changes
Makes sure the asset list is updated and redrawn correctly an local asset data
changes: Creating assets, removing assets, clearing assets, undo/redo, reading
files (with and without UI), parallel reading of asset data from files, ...

For redraws there now is a listener callback in the uiList type (C only) that
asks the asset lists if it needs a redraw after a given notifier. For the case
of asset data-block removal there is a ID remapping function in the asset list
now (just tags the list for a complete re-read). File reading, undo, redo and
the "Mark Asset"/"Clear Asset" operators explicitly tag asset lists showing
main data as dirty (via the global asset storage).
2021-03-11 18:05:18 +01:00
d71b7ff3ff Merge branch 'master' into ui-asset-view-template 2021-03-11 17:50:55 +01:00
048a5e5f56 Merge branch 'master' into ui-asset-view-template 2021-03-11 14:58:27 +01:00
622ca567eb Support passing ID type filter to the template
The ID type filter can be set as follows:
```
template_asset_view(..., filter_id_types={'filter_material', 'filter_object'})
```

I would have prefered if you could just create a
`bpy.types.AssetFilterSettings` object, fill that and pass it to the
template. But that doesn't seem possible right now without more complex
BPY additions.
Also, newer ID types (hair, point cloud, volume and simulation IDs) do
not support filtering, because their filtering flags exceed 32, meaning
we have to store them in 64 bit integers which RNA doesn't support for
enum properties...
2021-03-09 18:58:57 +01:00
7be8055a07 Merge branch 'master' into ui-asset-view-template 2021-03-09 14:59:37 +01:00
2f658677c6 Fix items not showing up if the preview is missing
No reason to skip adding the UI elements just because the preview is missing.
We can still show the text and allow dragging. Also makes it feel more
interactive while the previews load in a background thread.
2021-03-04 16:29:30 +01:00
5ccb47a97e Add own button/widget type for the asset previews
The new button type (UI_BTYPE_PREVIEW_TILE) shows the items similar to
the Asset Browser, or the File Browser in thumbnail display mode. That
is, previews bigger than normal buttons, with the name drawn centered
below it.

Would be nice if the File/Asset Browser and preview templates could
adopt that new button type, so that there's no ad-hoc drawing for these
anymore. That's for a future cleanup though.
2021-03-04 15:57:17 +01:00
9a6c22a764 Properly support mouse-selecting items in the asset view list
This was very glitchy before and just didn't work in most cases. The mouse
press event was simply caught by the preview icon button and didn't make its
way to the underlying list-row button.
2021-03-03 21:44:22 +01:00
317e78a792 EEVEE: Avoid old files with too many volume shadow sample being too slow
This clamp the volumetric shadow samples to the actual old max to avoid
problematic slowdown after the bugfix rB3a29c19b2bff.
2021-03-03 18:15:47 +01:00
Mikhail
2606f57bec EEVEE: SSS: Fix light leaking bewteen object at different depths
The SSS shader in Eevee has the following drawbacks (elaborated in {T79933}):

1. Glowing
2. Ringing. On low SSS jittering it is rendered a bunch of sharp lines
3. Overall blurriness due to the nature of the effect
4. Shadows near occlusions as in T65849
5. Too much SSS near the edge and on highly-tilted surfaces

{F9438636}
{F9427302}

In the original shader code there was a depth correction factor, as far as I can understand for fixing light bleeding from one object to another. But it was scaled incorrectly. I modified its scale to depend on SSS scale*radius and made it independent from the scene scale. The scale parameter (`-4`) is chosen so that it makes tilted surfaces to have visually the same SSS radius as straight surfaces (surfaces with normal pointed directly to the camera).

This depth correction factor alone fixes all the problems except for ringing (pt. 2). Because of float-point precision errors and irradiance interpolation some samples near the border of an object might leak light, causing sparkly or dashed (because of aliasing) patterns around the highlights. Switching from `texture()` to `texelFetch()` fixes this problem and makes textures on renders visually sharper.

An alternative solution would be to detect object borders and somehow prevent samples from crossing it. This can be done by:
1. Adding an `object_id` texture. I think it requires much more code changing and makes the shader more complicated. Again, `object_id` is not interpolatable.
2. Watch gradient of depth and discard samples if the gradient is too big. This solution depends on scene scale and requires more texture lookups. Since SSS is usually a minor effect, it probably doesn't require that level of accuracy.

I haven't notice it in practice, but I assume it can make visible SSS radius slightly off (up to 0.5 px in screen space, which is negligible). It is completely mitigated with render sampling.

Reviewed By: Clément Foucault
Differential Revision: https://developer.blender.org/D9740
2021-03-03 18:15:47 +01:00
b9451c4841 EEVEE: SSR: Check reflection ray against geometric normal
This improve self intersection prevention. Also reduce the bias
that was making a lot of rays not being shoot at grazing angles.
2021-03-03 18:15:47 +01:00
1c76b5aff0 EEVEE: Add ensure_valid_reflection to glossy closures
This is ported from Cycles and fixes issues with bump/normal mapping
giving weird reflections/lighting.

Fixes T81070 Specular light should be limited to normal pointing toward the camera
Fixes T78501 Normal mapping making specular artifact
2021-03-03 18:15:47 +01:00
23d705aacc Fix compiler issues introduced in recent commit.
{73af762e9cd595ea708647c02c7e74752d844e80}
2021-03-03 18:15:47 +01:00
ffd518617c Cleanup: use zero_v3 to clear colors. 2021-03-03 18:15:47 +01:00
c02ff5222e Cleanup: Make node_composite_cryptomatte CPP.
Core API of cryptomatte is also CPP.
2021-03-03 18:15:47 +01:00
ef832a5a42 Cleanup: clang tidy
Warnings:
* readability-inconsistent-declaration-parameter-name
* readability-redundant-smartptr-get
2021-03-03 18:15:47 +01:00
148a3095ca Cleanup: clang tidy
Can use const parameter.
2021-03-03 18:15:47 +01:00
049c34b86e Cleanup: clang tidy
Warning: else-after-return/break
2021-03-03 18:15:47 +01:00
4f8f541e02 Cleanup: make format 2021-03-03 18:15:47 +01:00
700824f247 Fix (unreported) Outliner missing updates copying IDs via python
Steps to reproduce:
- switch to Scripting workspace
- execute bpy.data.meshes['Cube'].copy()
- Outliner will not show the new mesh immediately

Now just send appropriate notifier.

Differential Revision: https://developer.blender.org/D10584
2021-03-03 18:15:47 +01:00
a0084630b9 Nodes: store references to bNodeLinks in NodeTreeRef
Sometimes it is useful to have this information available to be able
to read information from links.
2021-03-03 18:15:47 +01:00
418fdab1bc Fix crash when dragging nodes
The `bNodeLinkDrag` struct was NULL when dragging a node instead of
a link. It is allocated with `calloc` anyway, so this field doesn't
need to be explitely cleared.
2021-03-03 18:15:47 +01:00
caaa9b40ec Cleanup: minor changes to Python RNA pointer assignment
Don't assign the BPy_StructRNA a value which can be 'None',
instead, set it to NULL.
2021-03-03 18:15:47 +01:00
6045464c75 Cleanup: Use span and float matrix type in direct boolean code
This commit includes a few simple improvements to the direct mesh
boolean code added recently.
 - Passing the transforms and meshes to `direct_mesh_boolean` as spans
   makes the function easier to call from C++.
 - The definition of `TransMat`, was unecessary when we have the
   `float4x4` type already used elsewhere in C++ code.

Differential Revision: https://developer.blender.org/D10592
2021-03-03 18:15:46 +01:00
3522532cb2 Fix T85966: Wrong link picked when dragging multi-input socket
The socket drag operator stored the index of the last picked socket
into RNA in case the mouse cursor leaves the link while dragging.

This id was not unique which is why sometimes a link from an other node
with the same id is picked.

This patch changes the way the last picked link is stored and stores a
pointer to the link directly into bNodeLinkDrag struct instead.

Differential Revision: https://developer.blender.org/D10590
2021-03-03 18:15:46 +01:00
3bf8074d83 Cleanup: spelling, minor corrections
Also use doxygen comments for sculpt functions.
2021-03-03 18:15:46 +01:00
Patrick Busch
a7dc752f26 Python API: Expose CurveMapping Reset View function
The Python API for the curve mapping widget offers the `update`
function, but no way to reset the view to the clipping rectangle.

This commit adds a blenkernel function for this operation,
and exposes it to the CurvMapping RNA API. This allows addons
to display a more user-friendly view of the data in this widget.

Differential Revision: https://developer.blender.org/D10561
2021-03-03 18:15:46 +01:00
5d42e77bb2 Geometry Nodes: Attribute search drop-down
This commit adds a search for existing attributes when you click
on an attribute field. This is useful because otherwise you have
to remember which attributes should be available at each node in
the tree.

The fundamental complication is that this information is not
accessible statically. So the search data is only a cache from
the previous node tree evaluation. The information is added
with `BKE_nodetree_attribute_hint_add`, currently for every
input geometry socket for a single node.

This is only an initial implementation, and later versions will
expose the data type and domain of the attributes.

Differential Revision: https://developer.blender.org/D10519
2021-03-03 18:15:46 +01:00
89fa44440c UI: Rename search button variable
I landed D10527 in rB1a8aee0a7cec accidentally, and the version there was
missing a name change discussed in review. This commit just renames the
boolean variable controlling the special behavior for attribute search.

Original message meant for this change:
For geometry nodes we will use search buttons to display a list of
attributes available the last time the node tree was executed (D10519).
Because this list is just a hint, we need to be able to enter any string,
not just strings from the search items.

This patch adds a boolean option to string buttons to enable this.
The change is quite simple, changes to behavior are only required in
two places. The type-specific button struct changes help a lot here.

Differential Revision: https://developer.blender.org/D10527
2021-03-03 18:15:46 +01:00
a371a0e0e0 CMake/deps: Append platform CFLAGS and LDFLAGS to Python build to ensure compatibility with minimum macOS version
Similarly to other dependencies, the Python build should make use of the default CMake arguments. On macOS, for example, these arguments are required to set the deployment target correctly.

See also: https://devtalk.blender.org/t/compiling-latest-branch-on-macos-fails-undefined-symbol/17649

Reviewed By: brecht, sybren

Differential Revision: https://developer.blender.org/D10498
2021-03-03 18:15:46 +01:00
William Reynish
356d624f21 UI: Clean up labels and descriptions: "Draw" to "Display"
In Blender, we used to use the term 'draw' to refer to information
displayed to the user. For version 2.80, it was decided to change these
instances to 'display' instead. This was to avoid the ambiguity between
end-user drawing tools and display options.

From the Oxford English Dictionary:
 - Draw: produce (a picture or diagram) by making lines and marks on
   paper with a pencil, pen, etc.
 - Display: show (data or an image) on a computer, television, or
   other screen.

Therefore, we should use draw when referring to drawing tools for
making marks, but use display when referring to information
shown/displayed to the user. From a user POV, the computer displays
certain information, whereas the user draws a mark.

Apparently this change was not implemented consistently, so this patch
changes all remaining relevant instances of "draw".

Differential Revision: https://developer.blender.org/D10551
2021-03-03 18:15:46 +01:00
f5ede4ed8c UI: Expose an "is first search" boolean to search button callbacks
Currently when you open an RNA collection search button, like a
vertex group selector, the search filter isn't applied until you
start typing, in order to display every option at the start.
Otherwise they wouldn't be visible, since the search filter would
run for the current text.

Currently this check happens in one place, but it relies on the
`changed` value of `uiBut`. This is fine in the interface directory,
but anywhere else it would require exposing `uiBut.changed`, which
is probably too low-level to expose.

The solution is adding an `is_first` argument to the search callbacks,
which is nice for a few reasons:
  - They work at a higher level of abstraction, meaning they don't
    have to worry about how exactly to tell if this is the first
    search.
  - It makes it easier to do special behavior when the search menu
    is first opened.
  - Then, obviously, it makes that state accessible without including
    `interface_intern.h`.

Needed for attribute search: T85658

Differential Revision: https://developer.blender.org/D10528
2021-03-03 18:15:46 +01:00
3f8edc5da1 Fix Node UI Storage Threading Issues
Since the same node tree can be used in modifiers on different objects,
there can be multiple threads writing to the maps in the node tree UI
storage at the same time. The additions for attribute name hints and
error messages made it so this would often cause a crash or at least
an ASAN report. This patch adds locks to prevent multiple threads
from using the maps concurrently.

In a brief test I actually didn't observe a crash without the global
`bNodeTree` UI storage mutex, but I think it's necessary for the change
to be correct, and I did notice some unfreed memory without it anyway.
Ideally it would be in a node tree runtime struct though.

Differential Revision: https://developer.blender.org/D10577
2021-03-03 18:15:46 +01:00
8e126c3fa2 EEVEE: Fix incorrect volumetric light shadowing
The shadowing was computed on the light distance squared,
leaking to much light since it was integrating the extinction behind
the ligth itself.

Also bump the maximum shadow max step to the actual UI values. Otherwise
we get shadowing under evaluated because `dd` is too small.
2021-03-03 18:15:46 +01:00
bf3288e71a Fix (unreported) light cache bake crash
missing NULL check if there is no cache there to begin with.

Differential Revision: https://developer.blender.org/D10581
2021-03-03 18:15:46 +01:00
cd240d87ed Fix Fuild error with lite build
With audaspace disabled, function SEQ_add_sound_strip was declared as prototype.
2021-03-03 18:15:46 +01:00
8457a235a2 Sculpt: Expand Operator
Expand is a new operator for Sculpt Mode which is intended to be the main
tool for masking, Face Set editing, interacting with the filters and pattern
creation.

The fundamentals of the tool are similar to the previous sculpt.mask_expand
operator. It shares the same default shortcuts and functionality, making
the previous operator obsolete.

The shortcuts to execute the operator are:
- Shift + A: Expand mask
- Shift + Alt + A: Expand mask by normals
- Shift + W: Expand Face Set
- Shift + Alt + W: Resize current Face Set

The main changes compared to the previous sculpt.mask_expand operator are:
- Modal keymap, all operator options can be changed in real time while the
operator is running.
- Supports creating Mask, Face Sets and Sculpt Vertex Colors.
- Much better code, new features can be easily integrated.

Limitations:
- All Mask operations are supported for Sculpt Vertex colors, but not exposed
by default as their support is still experimental.
- Dyntopo does not support any Face Set or Sculpt Vertex Colors. functionality
 (they are not implemented in general for Dyntopo).
- Multires does not support any feature related to geodesic distances.
- Multires does not support vertex colors.
- Multires does not support recursions.
- In Multires, Face Sets snaping does not initialize all current enabled Face
Sets when toggling snapping.
- In Multires, Face Sets are created at base mesh level (works by this by
 design, like any other tool).
- Unlike the previous mask_expand operator, this one does not blur the mask
by default after finishing Expand as that does not fit the new design.
The mask can still be blurred by using the mask filter manually.

Reviewed By: JacquesLucke

Differential Revision: https://developer.blender.org/D10455
2021-03-03 18:15:46 +01:00
4ed86e0a11 Fix T86026: Crash Opening Cryptomatte File.
Not sure this fixes the root cause. It seems that memory corruption
happens in dynstr. This patch replaces dynstr with a streamstring.
2021-03-03 18:15:46 +01:00
5726029b86 Fix crash on NULL dereference
Caused by e1f3996d74, `seq_update_meta_disp_range()` did not check if
sequencer data exists.
2021-03-03 18:15:46 +01:00
d59ac439a1 Fix T86122: Performance Debug View Viewport Not Working
The performance debug menu isn't used that often anymore as render doc
also show the timings. This patch will make sure that enabling the
performance debug view (21) does not crash blender.
2021-03-03 18:15:46 +01:00
4ecdc400b5 Cleanup: remove unused arguments 2021-03-03 18:15:46 +01:00
d194b038d5 Fix error in rBb9e1cc931ee9
Bad copy paste...
2021-03-03 18:15:46 +01:00
5bc7acbdec Fix T86138 EEVEE: Bake Indirect Lighting crash in 2.93 with older files
This was caused by a missing version check.
2021-03-03 18:15:46 +01:00
ca69a303e1 Fix T86172: check if attribute is actually accessible
The crash happened when the density in the Point Distribute node was
above zero but so small, that no point was generated. In this case, there
was a point cloud component, but the point cloud was empty, making some
attributes unavailable.

One could also make more attributes available in this case, but that can
be done separately if necessary.
2021-03-03 18:15:46 +01:00
6c0c809524 EEVEE: Depth of field: Do not shrink highlights when using overblur
This fixes the issue of bokeh size being smaller when using overblur.

The additional overblur needs to be centered on the outer radius.
2021-03-03 18:15:46 +01:00
5dcf164932 VSE: Refactor meta operators
Move low level logic to module code and versioning logic to versioning code.

Metas strip position was handled in diffrent way compared to other strips.
This was introduced in c8b0d25794 as bugfix for T28158.
I disagree with such design. Meta strips should be handled in same way as
any other strips.

I have tested this change and haven't found any problems.
No problems after checking T28158 as well.
There should be no functional changes on user level.

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D9972
2021-03-03 18:15:46 +01:00
1a2ab21a2c Fix T85981, part II: bone's custom shape disappear on undo in some cases.
Nicely hidden bug in pose read library code, it was using the library
from the wrong ID as reference to relink the custom shape object pointer
(pose is data from Object, not Armature).
2021-03-03 18:15:46 +01:00
b88c7f7d13 Fix T85970: Incorrect scaling of meta strips
This is same issue as fixed by d857892553, but I forgot to check meta
strips. Meta strip output is always in render size.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D10560
2021-03-03 18:15:46 +01:00
c8a7e3a572 FFmpeg: Improve scrubbing performance
Applying negative offset to seek position before scanning doesnn't have
any effect. This change results in 1.5x faster seeking (random frame,
average value) in sample file with 30 frame GOP length.

If I am not mistaken, B frames can have pts that can be less than
pts of I frame that must be decoded. Even in this case though, B frame
packet will be stored after that I frame.

In addition, preseek value is de facto hardcoded so seeking would fail
if it could. This can be hard to spot though.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D10529
2021-03-03 18:15:46 +01:00
9d08f2d69a VSE: Refactor VSE strip loading code
Isolate RNA and operator logic from functions that create strips.
 - Operator specific code was removed from `SeqLoadInfo` structure and
   `SEQ_add_*` functions.
 - Strip loading code was removed from RNA and operator functions.
 - `SEQ_add_*` API was unified to work on `SeqLoadData` struct.
   Only exception is image strip, which require files to be loaded
   separately to strip creation itself. This is not ideal, but I think
   it's acceptable.
 - Some functions and variables were refactored so the code reads
   better.

There are minor functional changes (coincidental bugfixes):
 - Operator errors are reported per-strip. Previously they were not
   reported at all?
 - `new_sound()` RNA API function now create sound with length of 1
   if source file does not exist. Previously it created strip with
   length of 0.
 - Replace selection operator property wasn't working correctly.
   Fixed in this patch.

Reviewed By: sergey

Differential Revision: https://developer.blender.org/D9760
2021-03-03 18:15:46 +01:00
19e6db3d53 Geometry Nodes: show "Show Texture in texture tab" button
This enables the quick access button [to show the relevant Texture in
the Properties Editor] for textures used in geometry nodes.

This goes in line to what we do for other textures:
- modifier textures have this button
- particle textures have this button
- brush textures will soon have it, too (see D9813)

When outside of the Properties Editor, the button will always show (if a
texture is actually assigned), but will be inactive if no suiting
Properties Editor to show the texture in can be found.

Note this also changes the behavior to not show the button if _no_
texture is assigned (as in: we are still showing the "New" button).
Previously it was always there (e.g. for modifier textures), even if it
would take us to an empty texture tab. (Sure, we could add a texture
there then, but imho it makes more sense to just start showing it once a
texture is already there)

For this to work with geometry nodes, the following chages were done:
- implement foreachTexLink for geonode modifiers
- new buttons_texture_user_node_property_add() that stores prop as well
as node
- also use NODE_ACTIVE_TEXTURE flag in geometry nodetrees

notes:
- this still uses the first suiting (as in: pinning does not interfere)
Properties Editor it finds, this should (maybe?) find the _closest_
Property Editor instead (see related feedback in D9813).
- this will already show the button for brush textures as well
(disabled), but there is another mandatory change in an upcomming commit
to make it work there as well (see D9813)

ref. T85278

Maniphest Tasks: T85278

Differential Revision: https://developer.blender.org/D10293
2021-03-03 18:15:46 +01:00
eef2a348a7 Refactor UIList template for further changes and to fix some glitches
Could go further than that, I think this would benefit from some C++
features, but we can do that in another pass.
2021-03-02 16:23:32 +01:00
378b7eb2af Merge branch 'master' into ui-asset-view-template 2021-03-02 11:56:54 +01:00
3ce680f434 Merge branch 'master' into ui-asset-view-template 2021-03-01 17:11:21 +01:00
bc9eac28ba Initial AssetList API & use it to load assets for the asset view tempate
Lots of hacks and temporary code here. I wanted a first working version to find
possible pain points before getting into details.

Basic idea is to store each asset library in an `AssetList`, with a globally
accessible storage. Internally the list uses the File Browser's `FileList`
which already does a fair amount of heavy lifting (threaded file & external
asset reading, lazy loading of visible previews, ...). The File Browser could
access the global asset-list storage as well.

The asset view template uses the new asset list to load and display the assets.

Current state: {F9856940}

Open TODOs: https://developer.blender.org/maniphest/query/M6RWFxFSDor3/#R
2021-03-01 16:45:42 +01:00
796c599194 Add initial asset-view template, with dummy contents (palette colors)
Idea is to be able to display a list of assets in a layout, by giving it
some custom filtering settings (not done yet). This would be just a
uiList managed by Blender, displaying previews similar to the Asset
Browser.
I decided to use uiLists for this because it already deals with stuff
like writing its UI data to .blends (e.g. filtering and sort settings),
filtering and scrolling. But I think we'll have to do a number of
general improvements to them. Here I just added a new (C-only for now)
"flexible grid" list display type, which uses bigger previews and
behaves much better than the currend "grid" one.

There's a bit of hacking going on here and things will probably change.
For now I'm just interested in getting the basics done to see if the
direction is good.
2021-02-23 18:50:31 +01:00
62 changed files with 2698 additions and 551 deletions

View File

@@ -117,13 +117,19 @@ def register():
for cls in mod.classes:
register_class(cls)
# space_userprefs.py
from bpy.props import (
CollectionProperty,
EnumProperty,
IntProperty,
StringProperty,
)
from bpy.types import WindowManager
from bpy.types import (
AssetHandle,
WindowManager,
WorkSpace,
)
# space_userprefs.py
def addon_filter_items(_self, _context):
import addon_utils
@@ -165,6 +171,19 @@ def register():
)
# done...
# space_view3d.py
WorkSpace.active_pose_asset_index = IntProperty(
name="Active Pose Asset",
# TODO explain which list the index belongs to, or how it can be used to get the pose.
description="Per workspace index of the active pose asset"
)
# Register for window-manager. This is a global property that shouldn't be
# written to files.
WindowManager.pose_assets = CollectionProperty(
type=AssetHandle
)
# done...
def unregister():
from bpy.utils import unregister_class

View File

@@ -7000,6 +7000,29 @@ class VIEW3D_PT_context_properties(Panel):
rna_prop_ui.draw(self.layout, context, member, object, False)
class VIEW3D_PT_asset_testing(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Asset Testing"
bl_category = "Assets"
def draw(self, context):
layout = self.layout
wm = context.window_manager
workspace = context.workspace
layout.template_asset_view(
"pose_assets",
workspace,
"active_asset_library",
wm,
"pose_assets",
workspace,
"active_pose_asset_index"
)
# Grease Pencil Object - Multiframe falloff tools
class VIEW3D_PT_gpencil_multi_frame(Panel):
bl_space_type = 'VIEW_3D'
@@ -7713,6 +7736,7 @@ classes = (
VIEW3D_PT_transform_orientations,
VIEW3D_PT_overlay_gpencil_options,
VIEW3D_PT_context_properties,
VIEW3D_PT_asset_testing,
VIEW3D_PT_paint_vertex_context_menu,
VIEW3D_PT_paint_texture_context_menu,
VIEW3D_PT_paint_weight_context_menu,

View File

@@ -26,6 +26,7 @@
extern "C" {
#endif
struct AssetLibraryReference;
struct BlendDataReader;
struct BlendWriter;
struct ID;
@@ -45,6 +46,8 @@ struct AssetTagEnsureResult BKE_asset_metadata_tag_ensure(struct AssetMetaData *
const char *name);
void BKE_asset_metadata_tag_remove(struct AssetMetaData *asset_data, struct AssetTag *tag);
void BKE_asset_library_reference_init_default(struct AssetLibraryReference *library_ref);
struct PreviewImage *BKE_asset_metadata_preview_get_from_id(const struct AssetMetaData *asset_data,
const struct ID *owner_id);

View File

@@ -340,6 +340,8 @@ int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
const struct AssetLibraryReference *CTX_wm_asset_library(const bContext *C);
bool CTX_wm_interface_locked(const bContext *C);
/* Gets pointer to the dependency graph.

View File

@@ -332,6 +332,9 @@ typedef void (*uiListFilterItemsFunc)(struct uiList *ui_list,
struct PointerRNA *,
const char *propname);
/* Listen to notifiers. Only for lists defined in C. */
typedef void (*uiListListener)(struct uiList *ui_list, wmRegionListenerParams *params);
typedef struct uiListType {
struct uiListType *next, *prev;
@@ -341,6 +344,9 @@ typedef struct uiListType {
uiListDrawFilterFunc draw_filter;
uiListFilterItemsFunc filter_items;
/* For lists defined in C only. */
uiListListener listener;
/* RNA integration */
ExtensionRNA rna_ext;
} uiListType;

View File

@@ -110,6 +110,11 @@ void BKE_asset_metadata_tag_remove(AssetMetaData *asset_data, AssetTag *tag)
BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags);
}
void BKE_asset_library_reference_init_default(AssetLibraryReference *library_ref)
{
memcpy(library_ref, DNA_struct_default_get(AssetLibraryReference), sizeof(*library_ref));
}
/* Queries -------------------------------------------- */
PreviewImage *BKE_asset_metadata_preview_get_from_id(const AssetMetaData *UNUSED(asset_data),

View File

@@ -1398,6 +1398,11 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
}
const AssetLibraryReference *CTX_wm_asset_library(const bContext *C)
{
return ctx_data_pointer_get(C, "asset_library");
}
Depsgraph *CTX_data_depsgraph_pointer(const bContext *C)
{
Main *bmain = CTX_data_main(C);

View File

@@ -233,22 +233,30 @@ bool BKE_cryptomatte_find_name(const CryptomatteSession *session,
char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
{
DynStr *matte_id = BLI_dynstr_new();
std::stringstream ss;
ss.precision(9);
bool first = true;
LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) {
if (!first) {
BLI_dynstr_append(matte_id, ",");
ss << ',';
}
if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) {
BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name));
blender::StringRef entry_name(entry->name, BLI_strnlen(entry->name, sizeof(entry->name)));
if (!entry_name.is_empty()) {
ss << entry_name;
}
else {
BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash);
ss << '<' << std::scientific << entry->encoded_hash << '>';
}
first = false;
}
char *result = BLI_dynstr_get_cstring(matte_id);
BLI_dynstr_free(matte_id);
/* Convert result to C string. */
const std::string result_string = ss.str();
const char *c_str = result_string.c_str();
size_t result_len = result_string.size() + 1;
char *result = static_cast<char *>(MEM_mallocN(sizeof(char) * result_len, __func__));
memcpy(result, c_str, result_len);
return result;
}

View File

@@ -21,6 +21,8 @@
#include "BKE_cryptomatte.hh"
#include "BKE_image.h"
#include "DNA_node_types.h"
#include "RE_pipeline.h"
#include "MEM_guardedalloc.h"

View File

@@ -663,6 +663,7 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
default:
BLI_assert(false);
break;
}
break;
@@ -676,6 +677,7 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
case ATTR_DOMAIN_EDGE:
return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
default:
BLI_assert(false);
break;
}
break;
@@ -702,11 +704,13 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
case ATTR_DOMAIN_FACE:
return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute));
default:
BLI_assert(false);
break;
}
break;
}
default:
BLI_assert(false);
break;
}

View File

@@ -683,6 +683,9 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
if (dyn_data->items_filter_neworder) {
MEM_freeN(dyn_data->items_filter_neworder);
}
if (dyn_data->customdata) {
MEM_freeN(dyn_data->customdata);
}
MEM_freeN(dyn_data);
}
if (uilst->properties) {

View File

@@ -29,6 +29,7 @@
#include "BLT_translation.h"
#include "BKE_asset.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
@@ -53,6 +54,13 @@
/* -------------------------------------------------------------------- */
static void workspace_init_data(ID *id)
{
WorkSpace *workspace = (WorkSpace *)id;
BKE_asset_library_reference_init_default(&workspace->active_asset_library);
}
static void workspace_free_data(ID *id)
{
WorkSpace *workspace = (WorkSpace *)id;
@@ -180,7 +188,7 @@ IDTypeInfo IDType_ID_WS = {
.translation_context = BLT_I18NCONTEXT_ID_WORKSPACE,
.flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_MAKELOCAL | IDTYPE_FLAGS_NO_ANIMDATA,
.init_data = NULL,
.init_data = workspace_init_data,
.copy_data = NULL,
.free_data = workspace_free_data,
.make_local = NULL,

View File

@@ -53,6 +53,7 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_asset.h"
#include "BKE_attribute.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
@@ -1964,4 +1965,13 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
{
if (!DNA_struct_elem_find(
fd->filesdna, "WorkSpace", "AssetLibraryReference", "active_asset_library")) {
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
BKE_asset_library_reference_init_default(&workspace->active_asset_library);
}
}
}
}

View File

@@ -19,6 +19,7 @@ set(INC
../include
../../blenkernel
../../blenlib
../../blenloader
../../makesdna
../../makesrna
../../windowmanager
@@ -30,6 +31,7 @@ set(INC_SYS
set(SRC
asset_edit.cc
asset_list.cc
asset_ops.cc
)

View File

@@ -18,11 +18,23 @@
* \ingroup edasset
*/
#include <memory>
#include <string>
#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_report.h"
#include "BLI_utility_mixins.hh"
#include "BLO_readfile.h"
#include "DNA_ID.h"
#include "DNA_asset_types.h"
#include "DNA_space_types.h"
#include "MEM_guardedalloc.h"
#include "UI_interface_icons.h"
@@ -30,6 +42,8 @@
#include "ED_asset.h"
using namespace blender;
bool ED_asset_mark_id(const bContext *C, ID *id)
{
if (id->asset_data) {
@@ -45,6 +59,9 @@ bool ED_asset_mark_id(const bContext *C, ID *id)
UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true);
/* Important for asset storage to update properly! */
ED_assetlist_storage_tag_main_data_dirty();
return true;
}
@@ -57,6 +74,9 @@ bool ED_asset_clear_id(ID *id)
/* Don't clear fake user here, there's no guarantee that it was actually set by
* #ED_asset_mark_id(), it might have been something/someone else. */
/* Important for asset storage to update properly! */
ED_assetlist_storage_tag_main_data_dirty();
return true;
}
@@ -65,3 +85,135 @@ bool ED_asset_can_make_single_from_context(const bContext *C)
/* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */
return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != nullptr;
}
/* TODO better place? */
/* TODO What about the setter and the itemf? */
#include "BKE_preferences.h"
#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
int ED_asset_library_reference_to_enum_value(const AssetLibraryReference *library)
{
/* Simple case: Predefined repo, just set the value. */
if (library->type < ASSET_LIBRARY_CUSTOM) {
return library->type;
}
/* Note that the path isn't checked for validity here. If an invalid library path is used, the
* Asset Browser can give a nice hint on what's wrong. */
const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
&U, library->custom_library_index);
if (user_library) {
return ASSET_LIBRARY_CUSTOM + library->custom_library_index;
}
BLI_assert(0);
return ASSET_LIBRARY_LOCAL;
}
AssetLibraryReference ED_asset_library_reference_from_enum_value(int value)
{
AssetLibraryReference library;
/* Simple case: Predefined repo, just set the value. */
if (value < ASSET_LIBRARY_CUSTOM) {
library.type = value;
library.custom_library_index = -1;
BLI_assert(ELEM(value, ASSET_LIBRARY_LOCAL));
return library;
}
const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
&U, value - ASSET_LIBRARY_CUSTOM);
/* Note that the path isn't checked for validity here. If an invalid library path is used, the
* Asset Browser can give a nice hint on what's wrong. */
const bool is_valid = (user_library->name[0] && user_library->path[0]);
if (!user_library) {
library.type = ASSET_LIBRARY_LOCAL;
library.custom_library_index = -1;
}
else if (user_library && is_valid) {
library.custom_library_index = value - ASSET_LIBRARY_CUSTOM;
library.type = ASSET_LIBRARY_CUSTOM;
}
return library;
}
class AssetTemporaryIDConsumer : NonCopyable, NonMovable {
const AssetHandle &handle_;
TempLibraryContext *temp_lib_context_ = nullptr;
public:
AssetTemporaryIDConsumer(const AssetHandle &handle) : handle_(handle)
{
}
~AssetTemporaryIDConsumer()
{
if (temp_lib_context_) {
BLO_library_temp_free(temp_lib_context_);
}
}
ID *get_local_id()
{
return ED_assetlist_asset_local_id_get(&handle_);
}
ID *import_id(const AssetLibraryReference &asset_library,
ID_Type id_type,
Main &bmain,
ReportList &reports)
{
std::string asset_path = ED_assetlist_asset_filepath_get(asset_library, handle_);
if (asset_path.empty()) {
return nullptr;
}
char blend_file_path[FILE_MAX_LIBEXTRA];
char *group = NULL;
char *asset_name = NULL;
BLO_library_path_explode(asset_path.c_str(), blend_file_path, &group, &asset_name);
temp_lib_context_ = BLO_library_temp_load_id(
&bmain, blend_file_path, id_type, asset_name, &reports);
if (temp_lib_context_ == nullptr || temp_lib_context_->temp_id == nullptr) {
BKE_reportf(&reports, RPT_ERROR, "Unable to load %s from %s", asset_name, blend_file_path);
return nullptr;
}
BLI_assert(GS(temp_lib_context_->temp_id->name) == id_type);
return temp_lib_context_->temp_id;
}
};
AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle)
{
if (!handle) {
return nullptr;
}
return reinterpret_cast<AssetTempIDConsumer *>(
OBJECT_GUARDED_NEW(AssetTemporaryIDConsumer, *handle));
}
void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer)
{
OBJECT_GUARDED_SAFE_DELETE(*consumer, AssetTemporaryIDConsumer);
}
ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_,
const AssetLibraryReference *asset_library,
ID_Type id_type,
Main *bmain,
ReportList *reports)
{
if (!(consumer_ && asset_library && bmain && reports)) {
return nullptr;
}
AssetTemporaryIDConsumer *consumer = reinterpret_cast<AssetTemporaryIDConsumer *>(consumer_);
if (ID *local_id = consumer->get_local_id()) {
return local_id;
}
return consumer->import_id(*asset_library, id_type, *bmain, *reports);
}

View File

@@ -0,0 +1,563 @@
/*
* 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.
*/
/** \file
* \ingroup edasset
*
* Abstractions to manage runtime asset lists with a global cache for multiple UI elements to
* access.
* Internally this uses the #FileList API and structures from `filelist.c`. This is just because it
* contains most necessary logic already and there's not much time for a more long-term solution.
*/
#include <optional>
#include <string>
#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BLI_function_ref.hh"
#include "BLI_hash.hh"
#include "BLI_map.hh"
#include "BLI_path_util.h"
#include "BLI_utility_mixins.hh"
#include "DNA_asset_types.h"
#include "DNA_space_types.h"
#include "BKE_preferences.h"
#include "ED_asset.h"
#include "ED_fileselect.h"
#include "ED_screen.h"
#include "WM_api.h"
#include "WM_types.h"
/* XXX uses private header of file-space. */
#include "../space_file/filelist.h"
using namespace blender;
/**
* Wrapper to add logic to the AssetLibraryReference DNA struct.
*/
class AssetLibraryReferenceWrapper {
const AssetLibraryReference &reference_;
public:
/* Intentionally not `explicit`, allow implicit conversion for convienience. Might have to be
* NOLINT */
AssetLibraryReferenceWrapper(const AssetLibraryReference &reference);
~AssetLibraryReferenceWrapper() = default;
friend bool operator==(const AssetLibraryReferenceWrapper &a,
const AssetLibraryReferenceWrapper &b);
uint64_t hash() const;
};
AssetLibraryReferenceWrapper::AssetLibraryReferenceWrapper(const AssetLibraryReference &reference)
: reference_(reference)
{
}
bool operator==(const AssetLibraryReferenceWrapper &a, const AssetLibraryReferenceWrapper &b)
{
return (a.reference_.type == b.reference_.type) && (a.reference_.type == ASSET_LIBRARY_CUSTOM) ?
(a.reference_.custom_library_index == b.reference_.custom_library_index) :
true;
}
uint64_t AssetLibraryReferenceWrapper::hash() const
{
uint64_t hash1 = DefaultHash<decltype(reference_.type)>{}(reference_.type);
if (reference_.type != ASSET_LIBRARY_CUSTOM) {
return hash1;
}
uint64_t hash2 = DefaultHash<decltype(reference_.custom_library_index)>{}(
reference_.custom_library_index);
return hash1 ^ (hash2 * 33); /* Copied from DefaultHash for std::pair. */
}
/* -------------------------------------------------------------------- */
/** \name Asset list API
*
* Internally re-uses #FileList from the File Browser. It does all the heavy lifting already.
* \{ */
/**
* RAII wrapper for `FileList`
*/
class FileListWrapper : NonCopyable {
static void filelist_free_fn(FileList *list)
{
filelist_free(list);
MEM_freeN(list);
}
std::unique_ptr<FileList, decltype(&filelist_free_fn)> file_list_;
public:
explicit FileListWrapper(eFileSelectType filesel_type)
: file_list_(filelist_new(filesel_type), filelist_free_fn)
{
}
FileListWrapper(FileListWrapper &&other) = default;
FileListWrapper &operator=(FileListWrapper &&other) = default;
~FileListWrapper()
{
/* Destructs the owned pointer. */
file_list_ = nullptr;
}
operator FileList *() const
{
return file_list_.get();
}
};
class PreviewTimer : NonCopyable {
/* Non-owning! The Window-Manager registers and owns this. */
wmTimer *timer_ = nullptr;
public:
void ensureRunning(const bContext *C)
{
if (!timer_) {
timer_ = WM_event_add_timer_notifier(
CTX_wm_manager(C), CTX_wm_window(C), NC_ASSET | ND_ASSET_LIST_PREVIEW, 0.01);
}
}
void stop(const bContext *C)
{
if (timer_) {
WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), timer_);
timer_ = nullptr;
}
}
};
class AssetList : NonCopyable {
FileListWrapper filelist_;
AssetLibraryReference library_ref_;
PreviewTimer previews_timer_;
public:
AssetList() = delete;
AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref);
AssetList(AssetList &&other) = default;
~AssetList() = default;
void setup(const AssetFilterSettings *filter_settings = nullptr);
void fetch(const bContext &C);
void ensurePreviewsJob(bContext *C);
bool needsRefetch() const;
void iterate(AssetListIterFn fn) const;
bool listen(const wmNotifier &notifier) const;
void tagMainDataDirty() const;
void remapID(ID *id_old, ID *id_new) const;
StringRef filepath() const;
};
AssetList::AssetList(eFileSelectType filesel_type, const AssetLibraryReference &asset_library_ref)
: filelist_(filesel_type), library_ref_(asset_library_ref)
{
}
void AssetList::setup(const AssetFilterSettings *filter_settings)
{
FileList *files = filelist_;
/* TODO there should only be one (FileSelectAssetLibraryUID vs. AssetLibraryReference). */
FileSelectAssetLibraryUID file_asset_lib_ref;
file_asset_lib_ref.type = library_ref_.type;
file_asset_lib_ref.custom_library_index = library_ref_.custom_library_index;
bUserAssetLibrary *user_library = nullptr;
/* Ensure valid repository, or fall-back to local one. */
if (library_ref_.type == ASSET_LIBRARY_CUSTOM) {
BLI_assert(library_ref_.custom_library_index >= 0);
user_library = BKE_preferences_asset_library_find_from_index(
&U, library_ref_.custom_library_index);
}
/* Relevant bits from file_refresh(). */
/* TODO pass options properly. */
filelist_setrecursion(files, 1);
filelist_setsorting(files, FILE_SORT_ALPHA, false);
filelist_setlibrary(files, &file_asset_lib_ref);
/* TODO different filtering settings require the list to be reread. That's a no-go for when we
* want to allow showing the same asset library with different filter settings (as in,
* different ID types). The filelist needs to be made smarter somehow, maybe goes together with
* the plan to separate the view (preview caching, filtering, etc. ) from the data. */
filelist_setfilter_options(
files,
filter_settings != nullptr,
true,
true, /* Just always hide parent, prefer to not add an extra user option for this. */
FILE_TYPE_BLENDERLIB,
filter_settings ? filter_settings->id_types : FILTER_ID_ALL,
true,
"",
"");
char path[FILE_MAXDIR] = "";
if (user_library) {
BLI_strncpy(path, user_library->path, sizeof(path));
filelist_setdir(files, path);
}
else {
filelist_setdir(files, path);
}
}
void AssetList::fetch(const bContext &C)
{
FileList *files = filelist_;
if (filelist_needs_force_reset(files)) {
filelist_readjob_stop(files, CTX_wm_manager(&C));
filelist_clear(files);
}
if (filelist_needs_reading(files)) {
if (!filelist_pending(files)) {
filelist_readjob_start(files, NC_ASSET | ND_ASSET_LIST_READING, &C);
}
}
filelist_sort(files);
filelist_filter(files);
}
bool AssetList::needsRefetch() const
{
return filelist_needs_force_reset(filelist_);
}
void AssetList::iterate(AssetListIterFn fn) const
{
FileList *files = filelist_;
int numfiles = filelist_files_ensure(files);
for (int i = 0; i < numfiles; i++) {
FileDirEntry *file = filelist_file(files, i);
if (!fn(*file)) {
break;
}
}
}
void AssetList::ensurePreviewsJob(bContext *C)
{
FileList *files = filelist_;
int numfiles = filelist_files_ensure(files);
filelist_cache_previews_set(files, true);
filelist_file_cache_slidingwindow_set(files, 256);
/* TODO fetch all previews for now. */
filelist_file_cache_block(files, numfiles / 2);
filelist_cache_previews_update(files);
{
const bool previews_running = filelist_cache_previews_running(files);
if (previews_running) {
previews_timer_.ensureRunning(C);
}
else {
/* Preview is not running, no need to keep generating update events! */
previews_timer_.stop(C);
}
}
}
/**
* \return True if the asset-list needs a UI redraw.
*/
bool AssetList::listen(const wmNotifier &notifier) const
{
switch (notifier.category) {
case NC_ASSET:
if (ELEM(notifier.data, ND_ASSET_LIST_READING, ND_ASSET_LIST_PREVIEW)) {
return true;
}
if (ELEM(notifier.action, NA_ADDED, NA_REMOVED)) {
return true;
}
break;
}
return false;
}
void AssetList::tagMainDataDirty() const
{
if (filelist_needs_reset_on_main_changes(filelist_)) {
/* Full refresh of the file list if local asset data was changed. Refreshing this view
* is cheap and users expect this to be updated immediately. */
filelist_tag_force_reset(filelist_);
}
}
void AssetList::remapID(ID * /*id_old*/, ID * /*id_new*/) const
{
/* Trigger full refetch of the file list if main data was changed, don't even attempt remap
* pointers. We could give file list types a id-remap callback, but it's probably not worth it.
* Refreshing local file lists is relatively cheap. */
tagMainDataDirty();
}
StringRef AssetList::filepath() const
{
return filelist_dir(filelist_);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Runtime asset list cache
* \{ */
/**
* Class managing a global asset list map, each entry being a list for a specific asset library.
*/
class AssetListStorage {
using AssetListMap = Map<AssetLibraryReferenceWrapper, AssetList>;
public:
/* Purely static class, can't instantiate this. */
AssetListStorage() = delete;
static void fetch_library(const AssetLibraryReference &library_reference,
const bContext &C,
const AssetFilterSettings *filter_settings = nullptr);
static void destruct();
static AssetList *lookup_list(const AssetLibraryReference &library_ref);
static void tagMainDataDirty();
static void remapID(ID *id_new, ID *id_old);
private:
static std::optional<eFileSelectType> asset_library_reference_to_fileselect_type(
const AssetLibraryReference &library_reference);
using is_new_t = bool;
static std::tuple<AssetList &, is_new_t> ensure_list_storage(
const AssetLibraryReference &library_reference, eFileSelectType filesel_type);
static AssetListMap &global_storage();
};
void AssetListStorage::fetch_library(const AssetLibraryReference &library_reference,
const bContext &C,
const AssetFilterSettings *filter_settings)
{
std::optional filesel_type = asset_library_reference_to_fileselect_type(library_reference);
if (!filesel_type) {
return;
}
std::tuple list_create_info = ensure_list_storage(library_reference, *filesel_type);
AssetList &list = std::get<0>(list_create_info);
const bool is_new = std::get<1>(list_create_info);
if (is_new || list.needsRefetch()) {
list.setup(filter_settings);
list.fetch(C);
}
}
void AssetListStorage::destruct()
{
global_storage().~AssetListMap();
}
AssetList *AssetListStorage::lookup_list(const AssetLibraryReference &library_ref)
{
return global_storage().lookup_ptr(library_ref);
}
void AssetListStorage::tagMainDataDirty()
{
for (AssetList &list : global_storage().values()) {
list.tagMainDataDirty();
}
}
void AssetListStorage::remapID(ID *id_new, ID *id_old)
{
for (AssetList &list : global_storage().values()) {
list.remapID(id_new, id_old);
}
}
std::optional<eFileSelectType> AssetListStorage::asset_library_reference_to_fileselect_type(
const AssetLibraryReference &library_reference)
{
switch (library_reference.type) {
case ASSET_LIBRARY_CUSTOM:
return FILE_LOADLIB;
case ASSET_LIBRARY_LOCAL:
return FILE_MAIN_ASSET;
}
return std::nullopt;
}
std::tuple<AssetList &, AssetListStorage::is_new_t> AssetListStorage::ensure_list_storage(
const AssetLibraryReference &library_reference, eFileSelectType filesel_type)
{
AssetListMap &storage = global_storage();
if (AssetList *list = storage.lookup_ptr(library_reference)) {
return {*list, false};
}
storage.add(library_reference, AssetList(filesel_type, library_reference));
return {storage.lookup(library_reference), true};
}
/**
* Wrapper for Construct on First Use idiom, to avoid the Static Initialization Fiasco.
*/
AssetListStorage::AssetListMap &AssetListStorage::global_storage()
{
static AssetListMap global_storage_;
return global_storage_;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name C-API
* \{ */
/**
* Invoke asset list reading, potentially in a parallel job. Won't wait until the job is done,
* and may return earlier.
*/
void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference,
const AssetFilterSettings *filter_settings,
const bContext *C)
{
AssetListStorage::fetch_library(*library_reference, *C, filter_settings);
}
void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, bContext *C)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (list) {
list->ensurePreviewsJob(C);
}
}
/* TODO expose AssetList with an iterator? */
void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (list) {
list->iterate(fn);
}
}
std::string ED_assetlist_asset_filepath_get(const AssetLibraryReference &library_reference,
const AssetHandle &asset_handle)
{
if (asset_handle.file_data->id || !asset_handle.file_data->asset_data) {
return nullptr;
}
const char *library_path = ED_assetlist_library_path(&library_reference);
if (!library_path) {
return nullptr;
}
const char *asset_relpath = asset_handle.file_data->relpath;
char path[FILE_MAX_LIBEXTRA];
BLI_join_dirfile(path, sizeof(path), library_path, asset_relpath);
return path;
}
ID *ED_assetlist_asset_local_id_get(const AssetHandle *asset_handle)
{
return asset_handle->file_data->asset_data ? asset_handle->file_data->id : nullptr;
}
ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
{
ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data);
if (imbuf) {
return imbuf;
}
return filelist_geticon_image_ex(asset_handle->file_data);
}
const char *ED_assetlist_library_path(const AssetLibraryReference *library_reference)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (list) {
return list->filepath().data();
}
return nullptr;
}
/**
* \return True if the region needs a UI redraw.
*/
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (list) {
return list->listen(*notifier);
}
return false;
}
/**
* Tag all asset lists in the storage that show main data as needing an update (refetch).
*
* This only tags the data. If the asset list is visible on screen, the space is still responsible
* for ensuring the necessary redraw. It can use #ED_assetlist_listen() to check if the asset-list
* needs a redraw for a given notifier.
*/
void ED_assetlist_storage_tag_main_data_dirty()
{
AssetListStorage::tagMainDataDirty();
}
/**
* Remapping of ID pointers within the asset lists. Typically called when an ID is deleted to clear
* all references to it (\a id_new is null then).
*/
void ED_assetlist_storage_id_remap(ID *id_old, ID *id_new)
{
AssetListStorage::remapID(id_old, id_new);
}
/**
* Can't wait for static deallocation to run. There's nested data allocated with our guarded
* allocator, it will complain about unfreed memory on exit.
*/
void ED_assetlist_storage_exit()
{
AssetListStorage::destruct();
}
/** \} */

View File

@@ -20,17 +20,67 @@
#pragma once
#include "DNA_ID_enums.h"
#include "DNA_asset_types.h"
#ifdef __cplusplus
extern "C" {
#endif
struct AssetFilterSettings;
struct AssetLibraryReference;
struct bContext;
struct Main;
struct ReportList;
struct wmNotifier;
typedef struct AssetTempIDConsumer AssetTempIDConsumer;
bool ED_asset_mark_id(const struct bContext *C, struct ID *id);
bool ED_asset_clear_id(struct ID *id);
bool ED_asset_can_make_single_from_context(const struct bContext *C);
int ED_asset_library_reference_to_enum_value(const struct AssetLibraryReference *library);
struct AssetLibraryReference ED_asset_library_reference_from_enum_value(int value);
AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle);
void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer);
struct ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer,
const AssetLibraryReference *asset_library,
ID_Type id_type,
struct Main *bmain,
struct ReportList *reports);
void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
const struct AssetFilterSettings *filter_settings,
const struct bContext *C);
void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
struct bContext *C);
void ED_assetlist_storage_tag_main_data_dirty(void);
void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
void ED_assetlist_storage_exit(void);
ID *ED_assetlist_asset_local_id_get(const AssetHandle *asset_handle);
struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);
bool ED_assetlist_listen(const struct AssetLibraryReference *library_reference,
const struct wmNotifier *notifier);
void ED_operatortypes_asset(void);
#ifdef __cplusplus
}
#endif
/* TODO move to C++ asset-list header? */
#ifdef __cplusplus
std::string ED_assetlist_asset_filepath_get(const AssetLibraryReference &library_reference,
const AssetHandle &asset_handle);
# include "BLI_function_ref.hh"
/* Can return false to stop iterating. */
using AssetListIterFn = blender::FunctionRef<bool(FileDirEntry &)>;
void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn);
#endif

View File

@@ -136,13 +136,9 @@ void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y);
void ED_operatormacros_file(void);
void ED_fileselect_clear(struct wmWindowManager *wm,
struct Scene *owner_scene,
struct SpaceFile *sfile);
void ED_fileselect_clear(struct wmWindowManager *wm, struct SpaceFile *sfile);
void ED_fileselect_exit(struct wmWindowManager *wm,
struct Scene *owner_scene,
struct SpaceFile *sfile);
void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile);
bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile);
struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
@@ -166,7 +162,7 @@ int ED_file_icon(const struct FileDirEntry *file);
void ED_file_read_bookmarks(void);
void ED_file_change_dir_ex(struct bContext *C, struct bScreen *screen, struct ScrArea *area);
void ED_file_change_dir_ex(struct bContext *C, struct ScrArea *area);
void ED_file_change_dir(struct bContext *C);
void ED_file_path_button(struct bScreen *screen,

View File

@@ -34,6 +34,7 @@ extern "C" {
/* Struct Declarations */
struct ARegion;
struct AssetFilterSettings;
struct AutoComplete;
struct EnumPropertyItem;
struct FileSelectParams;
@@ -375,6 +376,9 @@ typedef enum {
/** Buttons with value >= #UI_BTYPE_SEARCH_MENU don't get undo pushes. */
UI_BTYPE_SEARCH_MENU = 41 << 9,
UI_BTYPE_EXTRA = 42 << 9,
/** A preview image (#PreviewImage), with text under it. Typically bigger than normal buttons and
* laid out in a grid, e.g. like the File Browser in thumbnail display mode. */
UI_BTYPE_PREVIEW_TILE = 43 << 9,
UI_BTYPE_HOTKEY_EVENT = 46 << 9,
/** Non-interactive image, used for splash screen */
UI_BTYPE_IMAGE = 47 << 9,
@@ -2159,6 +2163,22 @@ void uiTemplateList(uiLayout *layout,
int columns,
bool sort_reverse,
bool sort_lock);
struct uiList *uiTemplateList_ex(uiLayout *layout,
struct bContext *C,
const char *listtype_name,
const char *list_id,
struct PointerRNA *dataptr,
const char *propname,
struct PointerRNA *active_dataptr,
const char *active_propname,
const char *item_dyntip_propname,
int rows,
int maxrows,
int layout_type,
int columns,
bool sort_reverse,
bool sort_lock,
void *customdata);
void uiTemplateNodeLink(uiLayout *layout,
struct bContext *C,
struct bNodeTree *ntree,
@@ -2204,6 +2224,18 @@ int uiTemplateRecentFiles(struct uiLayout *layout, int rows);
void uiTemplateFileSelectPath(uiLayout *layout,
struct bContext *C,
struct FileSelectParams *params);
void uiTemplateAssetView(struct uiLayout *layout,
struct bContext *C,
const char *list_id,
struct PointerRNA *asset_library_dataptr,
const char *asset_library_propname,
struct PointerRNA *assets_dataptr,
const char *assets_propname,
struct PointerRNA *active_dataptr,
const char *active_propname,
const struct AssetFilterSettings *filter_settings,
const char *activate_opname,
const char *drag_opname);
/* items */
void uiItemO(uiLayout *layout, const char *name, int icon, const char *opname);
@@ -2457,6 +2489,7 @@ typedef struct uiDragColorHandle {
void ED_operatortypes_ui(void);
void ED_keymap_ui(struct wmKeyConfig *keyconf);
void ED_uilisttypes_ui(void);
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
bool UI_drop_color_poll(struct bContext *C,

View File

@@ -105,7 +105,10 @@ int UI_iconfile_get_index(const char *filename);
struct PreviewImage *UI_icon_to_preview(int icon_id);
int UI_icon_from_rnaptr(struct bContext *C, struct PointerRNA *ptr, int rnaicon, const bool big);
int UI_icon_from_rnaptr(const struct bContext *C,
struct PointerRNA *ptr,
int rnaicon,
const bool big);
int UI_icon_from_idcode(const int idcode);
int UI_icon_from_library(const struct ID *id);
int UI_icon_from_object_mode(const int mode);

View File

@@ -66,6 +66,7 @@ set(SRC
interface_region_tooltip.c
interface_regions.c
interface_style.c
interface_template_asset_view.cc
interface_template_search_menu.c
interface_template_search_operator.c
interface_templates.c

View File

@@ -714,15 +714,24 @@ static uiAfterFunc *ui_afterfunc_new(void)
* For executing operators after the button is pressed.
* (some non operator buttons need to trigger operators), see: T37795.
*
* \param context_but: A button from which to get the context from (`uiBut.context`) for the
* operator execution.
*
* \note Can only call while handling buttons.
*/
PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext, bool create_props)
static PointerRNA *ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot,
int opcontext,
bool create_props,
const uiBut *context_but)
{
PointerRNA *ptr = NULL;
uiAfterFunc *after = ui_afterfunc_new();
after->optype = ot;
after->opcontext = opcontext;
if (context_but && context_but->context) {
after->context = CTX_store_copy(context_but->context);
}
if (create_props) {
ptr = MEM_callocN(sizeof(PointerRNA), __func__);
@@ -733,6 +742,11 @@ PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext,
return ptr;
}
PointerRNA *ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext, bool create_props)
{
return ui_handle_afterfunc_add_operator_ex(ot, opcontext, create_props, NULL);
}
static void popup_check(bContext *C, wmOperator *op)
{
if (op && op->type->check) {
@@ -1057,6 +1071,43 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
data->applied = true;
}
/**
* \returns true if the operator was executed, otherwise false.
*/
static bool ui_list_invoke_item_operator(bContext *C,
const ARegion *region,
const wmEvent *event,
const char *name)
{
wmOperatorType *drag_ot = WM_operatortype_find(name, false);
const uiBut *hovered_but = ui_but_find_mouse_over(region, event);
if (!ui_but_context_poll_operator(C, drag_ot, hovered_but)) {
return false;
}
/* Allow the context to be set from the hovered button, so the list item draw callback can set
* context for the operators. */
ui_handle_afterfunc_add_operator_ex(drag_ot, WM_OP_INVOKE_DEFAULT, false, hovered_but);
return true;
}
static void ui_apply_but_LISTROW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
{
wmWindow *window = CTX_wm_window(C);
uiBut *listbox = ui_list_find_mouse_over(data->region, window->eventstate);
if (listbox) {
uiList *list = listbox->custom_data;
if (list && list->custom_activate_opname) {
ui_list_invoke_item_operator(
C, data->region, window->eventstate, list->custom_activate_opname);
}
}
ui_apply_but_ROW(C, block, but, data);
}
static void ui_apply_but_TEX(bContext *C, uiBut *but, uiHandleButtonData *data)
{
if (!data->str) {
@@ -1525,7 +1576,7 @@ static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const
*/
if (drag_info->is_xy_lock_init == false) {
/* first store the buttons original coords */
uiBut *but = ui_but_find_mouse_over_ex(region, xy_input[0], xy_input[1], true);
uiBut *but = ui_but_find_mouse_over_ex(region, xy_input[0], xy_input[1], true, NULL);
if (but) {
if (but->flag & UI_BUT_DRAG_LOCK) {
@@ -1596,7 +1647,7 @@ static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void
wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C);
uiBut *but = ui_but_find_mouse_over_ex(
region, drag_info->xy_init[0], drag_info->xy_init[1], true);
region, drag_info->xy_init[0], drag_info->xy_init[1], true, NULL);
if (but) {
ui_apply_but_undo(but);
@@ -2158,9 +2209,11 @@ static void ui_apply_but(
ui_apply_but_TOG(C, but, data);
break;
case UI_BTYPE_ROW:
case UI_BTYPE_LISTROW:
ui_apply_but_ROW(C, block, but, data);
break;
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
break;
case UI_BTYPE_TAB:
ui_apply_but_TAB(C, but, data);
break;
@@ -4165,7 +4218,7 @@ static uiBut *ui_but_list_row_text_activate(bContext *C,
uiButtonActivateType activate_type)
{
ARegion *region = CTX_wm_region(C);
uiBut *labelbut = ui_but_find_mouse_over_ex(region, event->x, event->y, true);
uiBut *labelbut = ui_but_find_mouse_over_ex(region, event->x, event->y, true, NULL);
if (labelbut && labelbut->type == UI_BTYPE_TEXT && !(labelbut->flag & UI_BUT_DISABLED)) {
/* exit listrow */
@@ -4659,6 +4712,15 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
if (but->dragpoin && but->imb && ui_but_contains_point_px_icon(but, data->region, event)) {
ret = WM_UI_HANDLER_CONTINUE;
}
/* Same special case handling for UI lists. Return CONTINUE so that a tweak or CLICK event
* will be sent for the list to work with. */
const uiBut *listbox = ui_list_find_mouse_over(data->region, event);
if (listbox) {
const uiList *ui_list = listbox->custom_data;
if (ui_list && ui_list->custom_drag_opname) {
ret = WM_UI_HANDLER_CONTINUE;
}
}
button_activate_state(C, but, BUTTON_STATE_EXIT);
return ret;
}
@@ -7683,6 +7745,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_IMAGE:
case UI_BTYPE_PROGRESS_BAR:
case UI_BTYPE_NODE_SOCKET:
case UI_BTYPE_PREVIEW_TILE:
retval = ui_do_but_EXIT(C, but, data, event);
break;
case UI_BTYPE_HISTOGRAM:
@@ -9017,6 +9080,109 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
return retval;
}
static bool ui_but_is_listrow(const uiBut *but)
{
return but->type == UI_BTYPE_LISTROW;
}
/**
* Activate the underlying list-row button, so the row is highlighted.
* Early exits if \a activate_dragging is true, but the custom drag operator fails to execute.
* Gives the wanted behavior where the item is activated on a tweak event when the custom drag
* operator is executed.
*/
static int ui_list_activate_hovered_row(bContext *C,
ARegion *region,
const uiList *ui_list,
const wmEvent *event,
bool activate_dragging)
{
const bool do_drag = activate_dragging && ui_list->custom_drag_opname;
if (do_drag) {
if (!ui_list_invoke_item_operator(C, region, event, ui_list->custom_drag_opname)) {
return WM_UI_HANDLER_CONTINUE;
}
}
const int *mouse_xy = ISTWEAK(event->type) ? &event->prevclickx : &event->x;
uiBut *listrow = ui_but_find_mouse_over_ex(
region, mouse_xy[0], mouse_xy[1], false, ui_but_is_listrow);
if (listrow) {
const char *custom_activate_opname = ui_list->custom_activate_opname;
/* Hacky: Ensure the custom activate operator is not called when the custom drag operator was.
* Only one should run! */
if (activate_dragging && do_drag) {
((uiList *)ui_list)->custom_activate_opname = NULL;
}
/* Simulate click on listrow button itself (which may be overlapped by another button). Also
* calls the custom activate operator (ui_list->custom_activate_opname). */
UI_but_execute(C, region, listrow);
((uiList *)ui_list)->custom_activate_opname = custom_activate_opname;
}
return WM_UI_HANDLER_BREAK;
}
static bool ui_list_is_hovering_draggable_but(bContext *C,
const uiList *list,
const ARegion *region,
const wmEvent *event)
{
/* On a tweak event, uses the coordinates from where tweaking was started. */
const int *mouse_xy = ISTWEAK(event->type) ? &event->prevclickx : &event->x;
const uiBut *hovered_but = ui_but_find_mouse_over_ex(
region, mouse_xy[0], mouse_xy[1], false, NULL);
if (list->custom_drag_opname) {
wmOperatorType *drag_ot = WM_operatortype_find(list->custom_drag_opname, false);
if (ui_but_context_poll_operator(C, drag_ot, hovered_but)) {
return true;
}
}
return (hovered_but && hovered_but->dragpoin);
}
static int ui_list_handle_click_drag(bContext *C,
const uiList *ui_list,
ARegion *region,
const wmEvent *event)
{
if (!ELEM(event->type, LEFTMOUSE, EVT_TWEAK_L)) {
return WM_HANDLER_CONTINUE;
}
int retval = WM_HANDLER_CONTINUE;
const bool is_draggable = ui_list_is_hovering_draggable_but(C, ui_list, region, event);
bool activate = false;
bool activate_dragging = false;
if (event->type == EVT_TWEAK_L) {
if (is_draggable) {
activate_dragging = true;
activate = true;
}
}
/* KM_CLICK is only sent after an uncaught release event, so the forground button gets all
* regular events (including mouse presses to start dragging) and this part only kicks in if it
* hasn't handled the release event. Note that if there's no overlaid button, the row selects
* on the press event already via regular UI_BTYPE_LISTROW handling. */
else if ((event->type == LEFTMOUSE) && (event->val == KM_CLICK)) {
activate = true;
}
if (activate) {
retval = ui_list_activate_hovered_row(C, region, ui_list, event, activate_dragging);
}
return retval;
}
static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *region, uiBut *listbox)
{
int retval = WM_UI_HANDLER_CONTINUE;
@@ -9050,7 +9216,10 @@ static int ui_handle_list_event(bContext *C, const wmEvent *event, ARegion *regi
}
}
if (val == KM_PRESS) {
if (ELEM(event->type, LEFTMOUSE, EVT_TWEAK_L)) {
retval = ui_list_handle_click_drag(C, ui_list, region, event);
}
else if (val == KM_PRESS) {
if ((ELEM(type, EVT_UPARROWKEY, EVT_DOWNARROWKEY) &&
!IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) ||
((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->ctrl &&

View File

@@ -2205,7 +2205,7 @@ int UI_icon_from_library(const ID *id)
return ICON_NONE;
}
int UI_icon_from_rnaptr(bContext *C, PointerRNA *ptr, int rnaicon, const bool big)
int UI_icon_from_rnaptr(const bContext *C, PointerRNA *ptr, int rnaicon, const bool big)
{
ID *id = NULL;

View File

@@ -1024,8 +1024,18 @@ void ui_draw_menu_item(const struct uiFontStyle *fstyle,
int state,
uiMenuItemSeparatorType separator_type,
int *r_xmax);
void ui_draw_preview_item(
const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state);
void ui_draw_preview_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
int state,
eFontStyle_Align text_align);
void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
const uchar text_col[4],
eFontStyle_Align text_align);
#define UI_TEXT_MARGIN_X 0.4f
#define UI_POPUP_MARGIN (UI_DPI_FAC * 12)
@@ -1110,10 +1120,12 @@ bool ui_but_contains_point_px(const uiBut *but, const struct ARegion *region, in
uiBut *ui_list_find_mouse_over(struct ARegion *region,
const struct wmEvent *event) ATTR_WARN_UNUSED_RESULT;
typedef bool (*uiButFindPoll)(const uiBut *but);
uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region,
const int x,
const int y,
const bool labeledit) ATTR_WARN_UNUSED_RESULT;
const bool labeledit,
uiButFindPoll find_poll) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_but_find_mouse_over(const struct ARegion *region,
const struct wmEvent *event) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_but_find_rect_over(const struct ARegion *region,

View File

@@ -265,10 +265,8 @@ bool ui_but_contains_point_px_icon(const uiBut *but, ARegion *region, const wmEv
}
/* x and y are only used in case event is NULL... */
uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
const int x,
const int y,
const bool labeledit)
uiBut *ui_but_find_mouse_over_ex(
const ARegion *region, const int x, const int y, const bool labeledit, uiButFindPoll find_poll)
{
uiBut *butover = NULL;
@@ -280,6 +278,9 @@ uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
ui_window_to_block_fl(region, block, &mx, &my);
LISTBASE_FOREACH_BACKWARD (uiBut *, but, &block->buttons) {
if (find_poll && find_poll(but) == false) {
continue;
}
if (ui_but_is_interactive(but, labeledit)) {
if (but->pie_dir != UI_RADIAL_NONE) {
if (ui_but_isect_pie_seg(block, but)) {
@@ -308,7 +309,7 @@ uiBut *ui_but_find_mouse_over_ex(const ARegion *region,
uiBut *ui_but_find_mouse_over(const ARegion *region, const wmEvent *event)
{
return ui_but_find_mouse_over_ex(region, event->x, event->y, event->ctrl != 0);
return ui_but_find_mouse_over_ex(region, event->x, event->y, event->ctrl != 0, NULL);
}
uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)

View File

@@ -599,8 +599,12 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
ui_draw_preview_item(
&data->fstyle, &rect, data->items.names[a], data->items.icons[a], state);
ui_draw_preview_item(&data->fstyle,
&rect,
data->items.names[a],
data->items.icons[a],
state,
UI_STYLE_TEXT_LEFT);
}
/* indicate more */

View File

@@ -0,0 +1,246 @@
/*
* 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.
*/
/** \file
* \ingroup edinterface
*/
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "BKE_screen.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "BLO_readfile.h"
#include "ED_asset.h"
#include "ED_screen.h"
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
#include "UI_interface.h"
#include "WM_api.h"
#include "interface_intern.h"
struct AssetViewListData {
AssetLibraryReference asset_library;
bScreen *screen;
};
static void asset_view_item_but_drag_set(uiBut *but,
AssetViewListData *list_data,
AssetHandle *asset_handle)
{
if (ID *id = asset_handle->file_data->id) {
UI_but_drag_set_id(but, id);
}
else {
const blender::StringRef asset_list_path = ED_assetlist_library_path(
&list_data->asset_library);
char blend_path[FILE_MAX_LIBEXTRA];
char path[FILE_MAX_LIBEXTRA];
BLI_join_dirfile(path, sizeof(path), asset_list_path.data(), asset_handle->file_data->relpath);
if (BLO_library_path_explode(path, blend_path, nullptr, nullptr)) {
ImBuf *imbuf = ED_assetlist_asset_image_get(asset_handle);
UI_but_drag_set_asset(but,
asset_handle->file_data->name,
BLI_strdup(blend_path),
asset_handle->file_data->blentype,
asset_handle->file_data->preview_icon_id,
imbuf,
1.0f);
}
}
}
static void asset_view_draw_item(uiList *ui_list,
bContext *UNUSED(C),
uiLayout *layout,
PointerRNA *UNUSED(dataptr),
PointerRNA *itemptr,
int UNUSED(icon),
PointerRNA *UNUSED(active_dataptr),
const char *UNUSED(active_propname),
int UNUSED(index),
int UNUSED(flt_flag))
{
AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata;
BLI_assert(RNA_struct_is_a(itemptr->type, &RNA_AssetHandle));
AssetHandle *asset_handle = (AssetHandle *)itemptr->data;
uiLayoutSetContextPointer(layout, "asset_handle", itemptr);
uiBlock *block = uiLayoutGetBlock(layout);
/* TODO ED_fileselect_init_layout(). Share somehow? */
float size_x = (96.0f / 20.0f) * UI_UNIT_X;
float size_y = (96.0f / 20.0f) * UI_UNIT_Y;
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
asset_handle->file_data->preview_icon_id,
asset_handle->file_data->name,
0,
0,
size_x,
size_y,
nullptr,
0,
0,
0,
0,
"");
ui_def_but_icon(but,
asset_handle->file_data->preview_icon_id,
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if (!ui_list->custom_drag_opname) {
asset_view_item_but_drag_set(but, list_data, asset_handle);
}
}
static void asset_view_listener(uiList *ui_list, wmRegionListenerParams *params)
{
AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata;
if (ED_assetlist_listen(&list_data->asset_library, params->notifier)) {
ED_region_tag_redraw(params->region);
}
}
static uiListType *UI_UL_asset_view()
{
uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__);
BLI_strncpy(list_type->idname, "UI_UL_asset_view", sizeof(list_type->idname));
list_type->draw_item = asset_view_draw_item;
list_type->listener = asset_view_listener;
return list_type;
}
void ED_uilisttypes_ui()
{
WM_uilisttype_add(UI_UL_asset_view());
}
static void asset_view_template_refresh_asset_collection(
const AssetLibraryReference &asset_library,
PointerRNA &assets_dataptr,
const char *assets_propname)
{
PropertyRNA *assets_prop = RNA_struct_find_property(&assets_dataptr, assets_propname);
if (!assets_prop) {
RNA_warning("Asset collection not found");
return;
}
if (!RNA_struct_is_a(RNA_property_pointer_type(&assets_dataptr, assets_prop),
&RNA_AssetHandle)) {
RNA_warning("Expected a collection property for AssetHandle items");
return;
}
RNA_property_collection_clear(&assets_dataptr, assets_prop);
ED_assetlist_iterate(&asset_library, [&](FileDirEntry &file) {
PointerRNA itemptr, fileptr;
RNA_property_collection_add(&assets_dataptr, assets_prop, &itemptr);
RNA_pointer_create(nullptr, &RNA_FileSelectEntry, &file, &fileptr);
RNA_pointer_set(&itemptr, "file_data", fileptr);
/* Copy name from file to asset-handle name ID-property. */
char name[MAX_NAME];
PropertyRNA *file_name_prop = RNA_struct_name_property(fileptr.type);
RNA_property_string_get(&fileptr, file_name_prop, name);
PropertyRNA *asset_name_prop = RNA_struct_name_property(&RNA_AssetHandle);
RNA_property_string_set(&itemptr, asset_name_prop, name);
return true;
});
}
void uiTemplateAssetView(uiLayout *layout,
bContext *C,
const char *list_id,
PointerRNA *asset_library_dataptr,
const char *asset_library_propname,
PointerRNA *assets_dataptr,
const char *assets_propname,
PointerRNA *active_dataptr,
const char *active_propname,
const AssetFilterSettings *filter_settings,
const char *activate_opname,
const char *drag_opname)
{
if (!list_id || !list_id[0]) {
RNA_warning("Asset view needs a valid identifier");
return;
}
uiLayout *col = uiLayoutColumn(layout, false);
PropertyRNA *asset_library_prop = RNA_struct_find_property(asset_library_dataptr,
asset_library_propname);
uiItemFullR(col, asset_library_dataptr, asset_library_prop, RNA_NO_INDEX, 0, 0, "", 0);
AssetLibraryReference asset_library = ED_asset_library_reference_from_enum_value(
RNA_property_enum_get(asset_library_dataptr, asset_library_prop));
ED_assetlist_storage_fetch(&asset_library, filter_settings, C);
ED_assetlist_ensure_previews_job(&asset_library, C);
asset_view_template_refresh_asset_collection(asset_library, *assets_dataptr, assets_propname);
AssetViewListData *list_data = (AssetViewListData *)MEM_mallocN(sizeof(*list_data),
"AssetViewListData");
list_data->asset_library = asset_library;
list_data->screen = CTX_wm_screen(C);
/* TODO can we have some kind of model-view API to handle referencing, filtering and lazy loading
* (of previews) of the items? */
uiList *list = uiTemplateList_ex(col,
C,
"UI_UL_asset_view",
list_id,
assets_dataptr,
assets_propname,
active_dataptr,
active_propname,
nullptr,
0,
0,
UILST_LAYOUT_BIG_PREVIEW_GRID,
0,
false,
false,
list_data);
list->custom_activate_opname = activate_opname;
list->custom_drag_opname = drag_opname;
if (!list) {
/* List creation failed. */
MEM_freeN(list_data);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/*
/*
* 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
@@ -105,6 +105,7 @@ typedef enum {
/* specials */
UI_WTYPE_ICON,
UI_WTYPE_ICON_LABEL,
UI_WTYPE_PREVIEW_TILE,
UI_WTYPE_SWATCH,
UI_WTYPE_RGB_PICKER,
UI_WTYPE_UNITVEC,
@@ -3942,6 +3943,14 @@ static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roun
widgetbase_draw(&wtb, wcol);
}
static void widget_preview_tile(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
const uiStyle *style = UI_style_get();
ui_draw_preview_item_stateless(
&style->widget, rect, but->drawstr, but->icon, wcol->text, UI_STYLE_TEXT_CENTER);
}
static void widget_menuiconbut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
@@ -4407,6 +4416,13 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.custom = widget_icon_has_anim;
break;
case UI_WTYPE_PREVIEW_TILE:
wt.draw = NULL;
/* Drawn via the `custom` callback. */
wt.text = NULL;
wt.custom = widget_preview_tile;
break;
case UI_WTYPE_SWATCH:
wt.custom = widget_swatch;
break;
@@ -4698,6 +4714,10 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
wt = widget_type(UI_WTYPE_BOX);
break;
case UI_BTYPE_PREVIEW_TILE:
wt = widget_type(UI_WTYPE_PREVIEW_TILE);
break;
case UI_BTYPE_EXTRA:
widget_draw_extra_mask(C, but, widget_type(UI_WTYPE_BOX), rect);
break;
@@ -4846,13 +4866,15 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
wt->draw(&wt->wcol, rect, state, roundboxalign);
}
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_ALPHA);
}
if (wt->text) {
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_ALPHA);
}
wt->text(fstyle, &wt->wcol, but, rect);
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_NONE);
wt->text(fstyle, &wt->wcol, but, rect);
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_NONE);
}
}
}
@@ -5374,17 +5396,20 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
}
}
void ui_draw_preview_item(
const uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state)
/**
* Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
* state. It just draws the preview and text directly.
*/
void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
const uchar text_col[4],
eFontStyle_Align text_align)
{
rcti trect = *rect;
const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
/* drawing button background */
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
wt->draw(&wt->wcol, rect, 0, 0);
/* draw icon in rect above the space reserved for the label */
rect->ymin += text_size;
@@ -5396,8 +5421,6 @@ void ui_draw_preview_item(
fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
/* text rect */
trect.xmin += 0;
trect.xmax = trect.xmin + font_dims[0] + U.widget_unit / 2;
trect.ymin += U.widget_unit / 2;
trect.ymax = trect.ymin + font_dims[1];
if (trect.xmax > rect->xmax - PREVIEW_PAD) {
@@ -5416,11 +5439,27 @@ void ui_draw_preview_item(
UI_fontstyle_draw(fstyle,
&trect,
drawstr,
wt->wcol.text,
text_col,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_CENTER,
.align = text_align,
});
}
}
void ui_draw_preview_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
int state,
eFontStyle_Align text_align)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
/* drawing button background */
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
wt->draw(&wt->wcol, rect, 0, 0);
ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
}
/** \} */

View File

@@ -161,6 +161,12 @@ void ED_region_do_listen(wmRegionListenerParams *params)
if (region->type && region->type->listener) {
region->type->listener(params);
}
LISTBASE_FOREACH (uiList *, list, &region->ui_lists) {
if (list->type && list->type->listener) {
list->type->listener(list, params);
}
}
}
/* only exported for WM */

View File

@@ -36,6 +36,7 @@
#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
@@ -111,6 +112,7 @@ const char *screen_context_dir[] = {
"selected_editable_fcurves",
"active_editable_fcurve",
"selected_editable_keyframes",
"asset_library",
NULL,
};
@@ -1024,6 +1026,14 @@ static eContextResult screen_ctx_selected_editable_keyframes(const bContext *C,
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_asset_library(const bContext *C, bContextDataResult *result)
{
WorkSpace *workspace = CTX_wm_workspace(C);
CTX_data_pointer_set(
result, &workspace->id, &RNA_AssetLibraryReference, &workspace->active_asset_library);
return CTX_RESULT_OK;
}
/* Registry of context callback functions. */
typedef eContextResult (*context_callback)(const bContext *C, bContextDataResult *result);
@@ -1098,6 +1108,7 @@ static void ensure_ed_screen_context_functions(void)
register_context_function("selected_visible_fcurves", screen_ctx_selected_visible_fcurves);
register_context_function("active_editable_fcurve", screen_ctx_active_editable_fcurve);
register_context_function("selected_editable_keyframes", screen_ctx_selected_editable_keyframes);
register_context_function("asset_library", screen_ctx_asset_library);
}
/* Entry point for the screen context. */

View File

@@ -129,6 +129,8 @@ void ED_spacetypes_init(void)
ED_screen_user_menu_register();
ED_uilisttypes_ui();
/* Gizmo types. */
ED_gizmotypes_button_2d();
ED_gizmotypes_dial_3d();

View File

@@ -48,6 +48,7 @@
#include "IMB_imbuf_types.h"
#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
@@ -531,7 +532,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
}
/* to make sure we show what is on disk */
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
}
ED_region_tag_redraw(region);
@@ -1065,7 +1066,7 @@ bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region)
return false;
}
/* Check if the library exists. */
if ((asset_params->asset_library.type == FILE_ASSET_LIBRARY_LOCAL) ||
if ((asset_params->asset_library.type == ASSET_LIBRARY_LOCAL) ||
filelist_is_dir(sfile->files, asset_params->base_params.dir)) {
return false;
}

View File

@@ -1846,7 +1846,7 @@ static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
/* refresh system directory menu */
fsmenu_refresh_system_category(fsmenu);
@@ -2323,7 +2323,7 @@ static int file_directory_new_exec(bContext *C, wmOperator *op)
sfile->scroll_offset = 0;
/* reload dir to make sure we're seeing what's in the directory */
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
if (do_diropen) {
BLI_strncpy(params->dir, path, sizeof(params->dir));
@@ -2574,7 +2574,7 @@ static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
if (params) {
params->flag ^= FILE_HIDE_DOT;
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
@@ -2834,7 +2834,7 @@ static int file_delete_exec(bContext *C, wmOperator *op)
}
}
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
ED_fileselect_clear(wm, sfile);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
return OPERATOR_FINISHED;

View File

@@ -1051,7 +1051,7 @@ static bool filelist_compare_asset_libraries(const FileSelectAssetLibraryUID *li
if (library_a->type != library_b->type) {
return false;
}
if (library_a->type == FILE_ASSET_LIBRARY_CUSTOM) {
if (library_a->type == ASSET_LIBRARY_CUSTOM) {
/* Don't only check the index, also check that it's valid. */
bUserAssetLibrary *library_ptr_a = BKE_preferences_asset_library_find_from_index(
&U, library_a->custom_library_index);
@@ -1154,7 +1154,7 @@ ImBuf *filelist_file_getimage(const FileDirEntry *file)
return file->preview_icon_id ? BKE_icon_imbuf_get_buffer(file->preview_icon_id) : NULL;
}
static ImBuf *filelist_geticon_image_ex(FileDirEntry *file)
ImBuf *filelist_geticon_image_ex(const FileDirEntry *file)
{
ImBuf *ibuf = NULL;
@@ -3443,7 +3443,7 @@ static void filelist_readjob_free(void *flrjv)
MEM_freeN(flrj);
}
void filelist_readjob_start(FileList *filelist, const bContext *C)
void filelist_readjob_start(FileList *filelist, int space_notifier, const bContext *C)
{
Main *bmain = CTX_data_main(C);
wmJob *wm_job;
@@ -3475,22 +3475,19 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
filelist_readjob_endjob(flrj);
filelist_readjob_free(flrj);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED, NULL);
WM_event_add_notifier(C, space_notifier | NA_JOB_FINISHED, NULL);
return;
}
/* setup job */
wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
CTX_data_scene(C),
filelist,
"Listing Dirs...",
WM_JOB_PROGRESS,
WM_JOB_TYPE_FILESEL_READDIR);
WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free);
WM_jobs_timer(wm_job,
0.01,
NC_SPACE | ND_SPACE_FILE_LIST,
NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED);
WM_jobs_timer(wm_job, 0.01, space_notifier, space_notifier | NA_JOB_FINISHED);
WM_jobs_callbacks(
wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob);
@@ -3498,12 +3495,12 @@ void filelist_readjob_start(FileList *filelist, const bContext *C)
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
void filelist_readjob_stop(wmWindowManager *wm, Scene *owner_scene)
void filelist_readjob_stop(FileList *filelist, wmWindowManager *wm)
{
WM_jobs_kill_type(wm, owner_scene, WM_JOB_TYPE_FILESEL_READDIR);
WM_jobs_kill_type(wm, filelist, WM_JOB_TYPE_FILESEL_READDIR);
}
int filelist_readjob_running(wmWindowManager *wm, Scene *owner_scene)
int filelist_readjob_running(FileList *filelist, wmWindowManager *wm)
{
return WM_jobs_test(wm, owner_scene, WM_JOB_TYPE_FILESEL_READDIR);
return WM_jobs_test(wm, filelist, WM_JOB_TYPE_FILESEL_READDIR);
}

View File

@@ -77,6 +77,7 @@ void filelist_init_icons(void);
void filelist_free_icons(void);
struct ImBuf *filelist_getimage(struct FileList *filelist, const int index);
struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index);
int filelist_geticon(struct FileList *filelist, const int index, const bool is_main);
@@ -140,9 +141,11 @@ struct BlendHandle *filelist_lib(struct FileList *filelist);
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group);
void filelist_freelib(struct FileList *filelist);
void filelist_readjob_start(struct FileList *filelist, const struct bContext *C);
void filelist_readjob_stop(struct wmWindowManager *wm, struct Scene *owner_scene);
int filelist_readjob_running(struct wmWindowManager *wm, struct Scene *owner_scene);
void filelist_readjob_start(struct FileList *filelist,
int space_notifier,
const struct bContext *C);
void filelist_readjob_stop(struct FileList *filelist, struct wmWindowManager *wm);
int filelist_readjob_running(struct FileList *filelist, struct wmWindowManager *wm);
bool filelist_cache_previews_update(struct FileList *filelist);
void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews);

View File

@@ -39,6 +39,7 @@
# include <unistd.h>
#endif
#include "DNA_asset_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
@@ -118,7 +119,7 @@ static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
asset_params = sfile->asset_params = MEM_callocN(sizeof(*asset_params),
"FileAssetSelectParams");
asset_params->base_params.details_flags = U_default.file_space_data.details_flags;
asset_params->asset_library.type = FILE_ASSET_LIBRARY_LOCAL;
asset_params->asset_library.type = ASSET_LIBRARY_LOCAL;
asset_params->asset_library.custom_library_index = -1;
}
@@ -419,26 +420,26 @@ static void fileselect_refresh_asset_params(FileAssetSelectParams *asset_params)
bUserAssetLibrary *user_library = NULL;
/* Ensure valid repository, or fall-back to local one. */
if (library->type == FILE_ASSET_LIBRARY_CUSTOM) {
if (library->type == ASSET_LIBRARY_CUSTOM) {
BLI_assert(library->custom_library_index >= 0);
user_library = BKE_preferences_asset_library_find_from_index(&U,
library->custom_library_index);
if (!user_library) {
library->type = FILE_ASSET_LIBRARY_LOCAL;
library->type = ASSET_LIBRARY_LOCAL;
}
}
switch (library->type) {
case FILE_ASSET_LIBRARY_LOCAL:
case ASSET_LIBRARY_LOCAL:
base_params->dir[0] = '\0';
break;
case FILE_ASSET_LIBRARY_CUSTOM:
case ASSET_LIBRARY_CUSTOM:
BLI_assert(user_library);
BLI_strncpy(base_params->dir, user_library->path, sizeof(base_params->dir));
break;
}
base_params->type = (library->type == FILE_ASSET_LIBRARY_LOCAL) ? FILE_MAIN_ASSET : FILE_LOADLIB;
base_params->type = (library->type == ASSET_LIBRARY_LOCAL) ? FILE_MAIN_ASSET : FILE_LOADLIB;
}
void fileselect_refresh_params(SpaceFile *sfile)
@@ -1046,7 +1047,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *region)
* Support updating the directory even when this isn't the active space
* needed so RNA properties update function isn't context sensitive, see T70255.
*/
void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area)
void ED_file_change_dir_ex(bContext *C, ScrArea *area)
{
/* May happen when manipulating non-active spaces. */
if (UNLIKELY(area->spacetype != SPACE_FILE)) {
@@ -1056,10 +1057,7 @@ void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area)
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
if (params) {
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = WM_windows_scene_get_from_screen(wm, screen);
if (LIKELY(scene != NULL)) {
ED_fileselect_clear(wm, scene, sfile);
}
ED_fileselect_clear(wm, sfile);
/* Clear search string, it is very rare to want to keep that filter while changing dir,
* and usually very annoying to keep it actually! */
@@ -1084,9 +1082,8 @@ void ED_file_change_dir_ex(bContext *C, bScreen *screen, ScrArea *area)
void ED_file_change_dir(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
ED_file_change_dir_ex(C, screen, area);
ED_file_change_dir_ex(C, area);
}
int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matched_file)
@@ -1182,11 +1179,11 @@ int autocomplete_file(struct bContext *C, char *str, void *UNUSED(arg_v))
return match;
}
void ED_fileselect_clear(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfile)
void ED_fileselect_clear(wmWindowManager *wm, SpaceFile *sfile)
{
/* only NULL in rare cases - T29734. */
if (sfile->files) {
filelist_readjob_stop(wm, owner_scene);
filelist_readjob_stop(sfile->files, wm);
filelist_freelib(sfile->files);
filelist_clear(sfile->files);
}
@@ -1196,7 +1193,7 @@ void ED_fileselect_clear(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfi
WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, NULL);
}
void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfile)
void ED_fileselect_exit(wmWindowManager *wm, SpaceFile *sfile)
{
if (!sfile) {
return;
@@ -1223,7 +1220,7 @@ void ED_fileselect_exit(wmWindowManager *wm, Scene *owner_scene, SpaceFile *sfil
folder_history_list_free(sfile);
if (sfile->files) {
ED_fileselect_clear(wm, owner_scene, sfile);
ED_fileselect_clear(wm, sfile);
filelist_free(sfile->files);
MEM_freeN(sfile->files);
sfile->files = NULL;

View File

@@ -206,7 +206,7 @@ static void file_exit(wmWindowManager *wm, ScrArea *area)
sfile->previews_timer = NULL;
}
ED_fileselect_exit(wm, NULL, sfile);
ED_fileselect_exit(wm, sfile);
}
static SpaceLink *file_duplicate(SpaceLink *sl)
@@ -360,13 +360,13 @@ static void file_refresh(const bContext *C, ScrArea *area)
sfile->recentnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_RECENT, params->dir);
if (filelist_needs_force_reset(sfile->files)) {
filelist_readjob_stop(wm, CTX_data_scene(C));
filelist_readjob_stop(sfile->files, wm);
filelist_clear(sfile->files);
}
if (filelist_needs_reading(sfile->files)) {
if (!filelist_pending(sfile->files)) {
filelist_readjob_start(sfile->files, C);
filelist_readjob_start(sfile->files, NC_SPACE | ND_SPACE_FILE_LIST, C);
}
}
@@ -847,7 +847,13 @@ static void file_space_subtype_item_extend(bContext *UNUSED(C),
}
}
static const char *file_context_dir[] = {"active_file", "id", NULL};
static const char *file_context_dir[] = {
"active_file",
"asset_handle",
"asset_library",
"id",
NULL,
};
static int /*eContextResult*/ file_context(const bContext *C,
const char *member,
@@ -878,6 +884,34 @@ static int /*eContextResult*/ file_context(const bContext *C,
CTX_data_pointer_set(result, &screen->id, &RNA_FileSelectEntry, file);
return CTX_RESULT_OK;
}
/* TODO this kind of handle is very weak. We need something proper that doesn't depend on file
* data. */
if (CTX_data_equals(member, "asset_handle")) {
FileDirEntry *file = filelist_file(sfile->files, params->active_file);
if (file == NULL || !file->asset_data) {
return CTX_RESULT_NO_DATA;
}
BLI_STATIC_ASSERT(sizeof(AssetHandle) == sizeof(FileDirEntry *),
"Expected AssetHandle to match FileDirEntry");
CTX_data_pointer_set(result, &screen->id, &RNA_AssetHandle, file);
return CTX_RESULT_OK;
}
if (CTX_data_equals(member, "asset_library")) {
FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile);
BLI_STATIC_ASSERT(offsetof(FileSelectAssetLibraryUID, type) ==
offsetof(AssetLibraryReference, type),
"Expected FileSelectAssetLibraryUID to match AssetLibraryReference");
BLI_STATIC_ASSERT(offsetof(FileSelectAssetLibraryUID, custom_library_index) ==
offsetof(AssetLibraryReference, custom_library_index),
"Expected FileSelectAssetLibraryUID to match AssetLibraryReference");
CTX_data_pointer_set(
result, &screen->id, &RNA_AssetLibraryReference, &asset_params->asset_library);
return CTX_RESULT_OK;
}
if (CTX_data_equals(member, "id")) {
const FileDirEntry *file = filelist_file(sfile->files, params->active_file);
if (file == NULL) {

View File

@@ -3445,7 +3445,15 @@ static void std_node_socket_draw(
case SOCK_RGBA: {
uiLayout *row = uiLayoutSplit(layout, 0.4f, false);
uiItemL(row, text, 0);
uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id;
if (node_tree->type == NTREE_GEOMETRY) {
node_geometry_add_attribute_search_button(node_tree, node, ptr, row);
}
else {
uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
}
break;
}
case SOCK_STRING: {

View File

@@ -38,9 +38,11 @@ struct bContext;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
struct uiBut;
struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
struct uiBlock;
#ifdef __cplusplus
extern "C" {

View File

@@ -50,6 +50,7 @@
#include "BLO_blend_validate.h"
#include "ED_asset.h"
#include "ED_gpencil.h"
#include "ED_object.h"
#include "ED_outliner.h"
@@ -268,6 +269,8 @@ static void ed_undo_step_post(bContext *C,
WM_toolsystem_refresh_active(C);
WM_toolsystem_refresh_screen_all(bmain);
ED_assetlist_storage_tag_main_data_dirty();
if (CLOG_CHECK(&LOG, 1)) {
BKE_undosys_print(wm->undo_stack);
}

View File

@@ -49,6 +49,7 @@
#include "DEG_depsgraph.h"
#include "ED_armature.h"
#include "ED_asset.h"
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_object.h"
@@ -172,6 +173,8 @@ void ED_editors_init(bContext *C)
ED_space_image_paint_update(bmain, wm, scene);
}
ED_assetlist_storage_tag_main_data_dirty();
SWAP(int, reports->flag, reports_flag_prev);
wm->op_undo_depth--;
}

View File

@@ -32,6 +32,13 @@
0 \
}
#define _DNA_DEFAULT_AssetLibraryReference \
{ \
.type = ASSET_LIBRARY_LOCAL, \
/* Not needed really (should be ignored for #ASSET_LIBRARY_LOCAL), but helps debugging. */ \
.custom_library_index = -1, \
}
/** \} */
/* clang-format on */

View File

@@ -20,6 +20,7 @@
#pragma once
#include "DNA_defs.h"
#include "DNA_listBase.h"
#ifdef __cplusplus
@@ -36,6 +37,14 @@ typedef struct AssetTag {
char name[64]; /* MAX_NAME */
} AssetTag;
typedef struct AssetFilterSettings {
/** Tags to match against. These are newly allocated, and compared against the
* #AssetMetaData.tags.
* TODO not used and doesn't do anything yet. */
ListBase tags; /* AssetTag */
uint64_t id_types; /* rna_enum_id_type_filter_items */
} AssetFilterSettings;
/**
* \brief The meta-data of an asset.
* By creating and giving this for a data-block (#ID.asset_data), the data-block becomes an asset.
@@ -62,6 +71,52 @@ typedef struct AssetMetaData {
char _pad[4];
} AssetMetaData;
typedef enum eAssetLibraryType {
/* For the future. Display assets bundled with Blender by default. */
// ASSET_LIBRARY_BUNDLED = 0,
/** Display assets from the current session (current "Main"). */
ASSET_LIBRARY_LOCAL = 1,
/* For the future. Display assets for the current project. */
// ASSET_LIBRARY_PROJECT = 2,
/** Display assets from custom asset libraries, as defined in the preferences
* (#bUserAssetLibrary). The name will be taken from #FileSelectParams.asset_library.idname
* then.
* In RNA, we add the index of the custom library to this to identify it by index. So keep
* this last! */
ASSET_LIBRARY_CUSTOM = 100,
} eAssetLibraryType;
/* TODO copy of FileSelectAssetLibraryUID */
/**
* Information to identify a asset library. May be either one of the predefined types (current
* 'Main', builtin library, project library), or a custom type as defined in the Preferences.
*
* If the type is set to #ASSET_LIBRARY_CUSTOM, `custom_library_index` must be set to identify the
* custom library. Otherwise it is not used.
*/
typedef struct AssetLibraryReference {
short type; /* eAssetLibraryType */
char _pad1[2];
/**
* If showing a custom asset library (#ASSET_LIBRARY_CUSTOM), this is the index of the
* #bUserAssetLibrary within #UserDef.asset_libraries.
* Should be ignored otherwise (but better set to -1 then, for sanity and debugging).
*/
int custom_library_index;
} AssetLibraryReference;
/**
* Not part of the core design, we should try to get rid of it. Only needed to wrap FileDirEntry
* into a type with PropertyGroup as base, so we can have an RNA collection of #AssetHandle's to
* pass to the UI.
*/
#
#
typedef struct AssetHandle {
struct FileDirEntry *file_data;
} AssetHandle;
#ifdef __cplusplus
}
#endif

View File

@@ -269,6 +269,9 @@ typedef struct uiListDyn {
int resize;
int resize_prev;
/* Allocated custom data. Free'ed together with the uiList (and when re-assigning). */
void *customdata;
/* Filtering data. */
/** Items_len length. */
int *items_filter_flags;
@@ -300,6 +303,12 @@ typedef struct uiList { /* some list UI data need to be saved in file */
int filter_flag;
int filter_sort_flag;
/** Operator executed when activating an item. */
const char *custom_activate_opname;
/** Operator executed when dragging an item (item gets activated too, without running
* custom_activate_opname above). */
const char *custom_drag_opname;
/* Custom sub-classes properties. */
IDProperty *properties;
@@ -583,6 +592,7 @@ enum {
UILST_LAYOUT_DEFAULT = 0,
UILST_LAYOUT_COMPACT = 1,
UILST_LAYOUT_GRID = 2,
UILST_LAYOUT_BIG_PREVIEW_GRID = 3,
};
/** #uiList.flag */

View File

@@ -696,14 +696,14 @@ typedef enum eSpaceSeq_OverlayType {
* Information to identify a asset library. May be either one of the predefined types (current
* 'Main', builtin library, project library), or a custom type as defined in the Preferences.
*
* If the type is set to #FILE_ASSET_LIBRARY_CUSTOM, idname must have the name to identify the
* If the type is set to #ASSET_LIBRARY_CUSTOM, idname must have the name to identify the
* custom library. Otherwise idname is not used.
*/
typedef struct FileSelectAssetLibraryUID {
short type; /* eFileAssetLibrary_Type */
char _pad[2];
/**
* If showing a custom asset library (#FILE_ASSET_LIBRARY_CUSTOM), this is the index of the
* If showing a custom asset library (#ASSET_LIBRARY_CUSTOM), this is the index of the
* #bUserAssetLibrary within #UserDef.asset_libraries.
* Should be ignored otherwise (but better set to -1 then, for sanity and debugging).
*/
@@ -868,22 +868,6 @@ typedef enum eFileBrowse_Mode {
FILE_BROWSE_MODE_ASSETS = 1,
} eFileBrowse_Mode;
typedef enum eFileAssetLibrary_Type {
/* For the future. Display assets bundled with Blender by default. */
// FILE_ASSET_LIBRARY_BUNDLED = 0,
/** Display assets from the current session (current "Main"). */
FILE_ASSET_LIBRARY_LOCAL = 1,
/* For the future. Display assets for the current project. */
// FILE_ASSET_LIBRARY_PROJECT = 2,
/** Display assets from custom asset libraries, as defined in the preferences
* (#bUserAssetLibrary). The name will be taken from #FileSelectParams.asset_library.idname
* then.
* In RNA, we add the index of the custom library to this to identify it by index. So keep
* this last! */
FILE_ASSET_LIBRARY_CUSTOM = 100,
} eFileAssetLibrary_Type;
/* FileSelectParams.display */
enum eFileDisplayType {
/** Internal (not exposed to users): Keep whatever display type was used during the last File

View File

@@ -23,6 +23,7 @@
#pragma once
#include "DNA_ID.h"
#include "DNA_asset_types.h"
#ifdef __cplusplus
extern "C" {
@@ -135,6 +136,10 @@ typedef struct WorkSpace {
/** Info text from modal operators (runtime). */
char *status_text;
/** Workspace-wide active asset library, for asset UIs to use (e.g. asset view UI template). The
* Asset Browser has its own and doesn't use this. */
AssetLibraryReference active_asset_library;
} WorkSpace;
/**

View File

@@ -152,6 +152,7 @@
/* DNA_asset_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(AssetMetaData);
SDNA_DEFAULT_DECL_STRUCT(AssetLibraryReference);
/* DNA_armature_defaults.h */
SDNA_DEFAULT_DECL_STRUCT(bArmature);
@@ -346,6 +347,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
/* DNA_asset_defaults.h */
SDNA_DEFAULT_DECL(AssetMetaData),
SDNA_DEFAULT_DECL(AssetLibraryReference),
/* DNA_armature_defaults.h */
SDNA_DEFAULT_DECL(bArmature),

View File

@@ -71,6 +71,9 @@ extern StructRNA RNA_ArrayGpencilModifier;
extern StructRNA RNA_ArrayModifier;
extern StructRNA RNA_Attribute;
extern StructRNA RNA_AttributeGroup;
extern StructRNA RNA_AssetFilterSettings;
extern StructRNA RNA_AssetHandle;
extern StructRNA RNA_AssetLibraryReference;
extern StructRNA RNA_AssetMetaData;
extern StructRNA RNA_AssetTag;
extern StructRNA RNA_BackgroundImage;
@@ -472,6 +475,7 @@ extern StructRNA RNA_Paint;
extern StructRNA RNA_PaintCurve;
extern StructRNA RNA_PaintToolSlot;
extern StructRNA RNA_Palette;
extern StructRNA RNA_PaletteColors;
extern StructRNA RNA_PaletteColor;
extern StructRNA RNA_Panel;
extern StructRNA RNA_Particle;

View File

@@ -243,6 +243,22 @@ extern const EnumPropertyItem *rna_enum_attribute_domain_itemf(struct ID *id, bo
extern const EnumPropertyItem rna_enum_collection_color_items[];
/**
* For ID filters (#FILTER_ID_AC, #FILTER_ID_AR, ...) an int isn't enough. This version allows 64
* bit integers. So can't use the regular #EnumPropertyItem. Would be nice if RNA supported this
* itself.
*
* Meant to be used with #RNA_def_property_boolean_sdna() which supports 64 bit flags as well.
*/
struct IDFilterEnumPropertyItem {
const uint64_t flag;
const char *identifier;
const int icon;
const char *name;
const char *description;
};
extern const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[];
/* API calls */
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
int rna_node_tree_idname_to_enum(const char *idname);

View File

@@ -4290,7 +4290,6 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_animviz.c", NULL, RNA_def_animviz},
{"rna_armature.c", "rna_armature_api.c", RNA_def_armature},
{"rna_attribute.c", NULL, RNA_def_attribute},
{"rna_asset.c", NULL, RNA_def_asset},
{"rna_boid.c", NULL, RNA_def_boid},
{"rna_brush.c", NULL, RNA_def_brush},
{"rna_cachefile.c", NULL, RNA_def_cachefile},
@@ -4345,6 +4344,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_simulation.c", NULL, RNA_def_simulation},
#endif
{"rna_space.c", "rna_space_api.c", RNA_def_space},
{"rna_asset.c", NULL, RNA_def_asset}, /* After spaces! */
{"rna_speaker.c", NULL, RNA_def_speaker},
{"rna_test.c", NULL, RNA_def_test},
{"rna_text.c", "rna_text_api.c", RNA_def_text},

View File

@@ -126,6 +126,97 @@ static const EnumPropertyItem rna_enum_override_library_property_operation_items
{0, NULL, 0, NULL, NULL},
};
/**
* \note Uses #IDFilterEnumPropertyItem, not EnumPropertyItem to support 64 bit items.
*/
const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[] = {
/* Datablocks */
{FILTER_ID_AC, "filter_action", ICON_ANIM_DATA, "Actions", "Show Action data-blocks"},
{FILTER_ID_AR,
"filter_armature",
ICON_ARMATURE_DATA,
"Armatures",
"Show Armature data-blocks"},
{FILTER_ID_BR, "filter_brush", ICON_BRUSH_DATA, "Brushes", "Show Brushes data-blocks"},
{FILTER_ID_CA, "filter_camera", ICON_CAMERA_DATA, "Cameras", "Show Camera data-blocks"},
{FILTER_ID_CF, "filter_cachefile", ICON_FILE, "Cache Files", "Show Cache File data-blocks"},
{FILTER_ID_CU, "filter_curve", ICON_CURVE_DATA, "Curves", "Show Curve data-blocks"},
{FILTER_ID_GD,
"filter_grease_pencil",
ICON_GREASEPENCIL,
"Grease Pencil",
"Show Grease pencil data-blocks"},
{FILTER_ID_GR,
"filter_group",
ICON_OUTLINER_COLLECTION,
"Collections",
"Show Collection data-blocks"},
{FILTER_ID_HA, "filter_hair", ICON_HAIR_DATA, "Hairs", "Show/hide Hair data-blocks"},
{FILTER_ID_IM, "filter_image", ICON_IMAGE_DATA, "Images", "Show Image data-blocks"},
{FILTER_ID_LA, "filter_light", ICON_LIGHT_DATA, "Lights", "Show Light data-blocks"},
{FILTER_ID_LP,
"filter_light_probe",
ICON_OUTLINER_DATA_LIGHTPROBE,
"Light Probes",
"Show Light Probe data-blocks"},
{FILTER_ID_LS,
"filter_linestyle",
ICON_LINE_DATA,
"Freestyle Linestyles",
"Show Freestyle's Line Style data-blocks"},
{FILTER_ID_LT, "filter_lattice", ICON_LATTICE_DATA, "Lattices", "Show Lattice data-blocks"},
{FILTER_ID_MA,
"filter_material",
ICON_MATERIAL_DATA,
"Materials",
"Show Material data-blocks"},
{FILTER_ID_MB, "filter_metaball", ICON_META_DATA, "Metaballs", "Show Metaball data-blocks"},
{FILTER_ID_MC,
"filter_movie_clip",
ICON_TRACKER_DATA,
"Movie Clips",
"Show Movie Clip data-blocks"},
{FILTER_ID_ME, "filter_mesh", ICON_MESH_DATA, "Meshes", "Show Mesh data-blocks"},
{FILTER_ID_MSK, "filter_mask", ICON_MOD_MASK, "Masks", "Show Mask data-blocks"},
{FILTER_ID_NT, "filter_node_tree", ICON_NODETREE, "Node Trees", "Show Node Tree data-blocks"},
{FILTER_ID_OB, "filter_object", ICON_OBJECT_DATA, "Objects", "Show Object data-blocks"},
{FILTER_ID_PA,
"filter_particle_settings",
ICON_PARTICLE_DATA,
"Particles Settings",
"Show Particle Settings data-blocks"},
{FILTER_ID_PAL, "filter_palette", ICON_COLOR, "Palettes", "Show Palette data-blocks"},
{FILTER_ID_PC,
"filter_paint_curve",
ICON_CURVE_BEZCURVE,
"Paint Curves",
"Show Paint Curve data-blocks"},
{FILTER_ID_PT,
"filter_pointcloud",
ICON_POINTCLOUD_DATA,
"Point Clouds",
"Show/hide Point Cloud data-blocks"},
{FILTER_ID_SCE, "filter_scene", ICON_SCENE_DATA, "Scenes", "Show Scene data-blocks"},
{FILTER_ID_SIM,
"filter_simulation",
ICON_PHYSICS,
"Simulations",
"Show Simulation data-blocks"}, /* TODO: Use correct icon. */
{FILTER_ID_SPK, "filter_speaker", ICON_SPEAKER, "Speakers", "Show Speaker data-blocks"},
{FILTER_ID_SO, "filter_sound", ICON_SOUND, "Sounds", "Show Sound data-blocks"},
{FILTER_ID_TE, "filter_texture", ICON_TEXTURE_DATA, "Textures", "Show Texture data-blocks"},
{FILTER_ID_TXT, "filter_text", ICON_TEXT, "Texts", "Show Text data-blocks"},
{FILTER_ID_VF, "filter_font", ICON_FONT_DATA, "Fonts", "Show Font data-blocks"},
{FILTER_ID_VO, "filter_volume", ICON_VOLUME_DATA, "Volumes", "Show/hide Volume data-blocks"},
{FILTER_ID_WO, "filter_world", ICON_WORLD_DATA, "Worlds", "Show World data-blocks"},
{FILTER_ID_WS,
"filter_work_space",
ICON_WORKSPACE,
"Workspaces",
"Show workspace data-blocks"},
{0, NULL, 0, NULL, NULL},
};
#ifdef RNA_RUNTIME
# include "DNA_anim_types.h"

View File

@@ -35,6 +35,8 @@
# include "BLI_listbase.h"
# include "ED_asset.h"
# include "RNA_access.h"
static AssetTag *rna_AssetMetaData_tag_new(AssetMetaData *asset_data,
@@ -129,6 +131,87 @@ static void rna_AssetMetaData_active_tag_range(
*max = *softmax = MAX2(asset_data->tot_tags - 1, 0);
}
static PointerRNA rna_AssetHandle_file_data_get(PointerRNA *ptr)
{
AssetHandle *asset_handle = ptr->data;
return rna_pointer_inherit_refine(ptr, &RNA_AssetHandle, asset_handle->file_data);
}
static void rna_AssetHandle_file_data_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *UNUSED(reports))
{
AssetHandle *asset_handle = ptr->data;
asset_handle->file_data = value.data;
}
int rna_asset_library_reference_get(const AssetLibraryReference *library)
{
return ED_asset_library_reference_to_enum_value(library);
}
void rna_asset_library_reference_set(AssetLibraryReference *library, int value)
{
*library = ED_asset_library_reference_from_enum_value(value);
}
const EnumPropertyItem *rna_asset_library_reference_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
const EnumPropertyItem predefined_items[] = {
/* For the future. */
// {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
{ASSET_LIBRARY_LOCAL,
"LOCAL",
ICON_BLENDER,
"Current File",
"Show the assets currently available in this Blender session"},
{0, NULL, 0, NULL, NULL},
};
EnumPropertyItem *item = NULL;
int totitem = 0;
/* Add separator if needed. */
if (!BLI_listbase_is_empty(&U.asset_libraries)) {
const EnumPropertyItem sepr = {0, "", 0, "Custom", NULL};
RNA_enum_item_add(&item, &totitem, &sepr);
}
int i = 0;
for (bUserAssetLibrary *user_library = U.asset_libraries.first; user_library;
user_library = user_library->next, i++) {
/* Note that the path itself isn't checked for validity here. If an invalid library path is
* used, the Asset Browser can give a nice hint on what's wrong. */
const bool is_valid = (user_library->name[0] && user_library->path[0]);
if (!is_valid) {
continue;
}
/* Use library path as description, it's a nice hint for users. */
EnumPropertyItem tmp = {ASSET_LIBRARY_CUSTOM + i,
user_library->name,
ICON_NONE,
user_library->name,
user_library->path};
RNA_enum_item_add(&item, &totitem, &tmp);
}
if (totitem) {
const EnumPropertyItem sepr = {0, "", 0, "Built-in", NULL};
RNA_enum_item_add(&item, &totitem, &sepr);
}
/* Add predefined items. */
RNA_enum_items_add(&item, &totitem, predefined_items);
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
#else
static void rna_def_asset_tag(BlenderRNA *brna)
@@ -181,6 +264,33 @@ static void rna_def_asset_tags_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
static void rna_def_asset_filter_settings(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "AssetFilterSettings", NULL);
RNA_def_struct_ui_text(srna, "Asset Filter Settings", "");
prop = RNA_def_property(srna, "tags", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "AssetTag");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop,
"Tags",
"Custom tags (name tokens) for the asset, used for filtering and "
"general asset management");
RNA_def_property_srna(prop, "AssetTags");
for (int i = 0; rna_enum_id_type_filter_items[i].identifier; i++) {
prop = RNA_def_property(
srna, rna_enum_id_type_filter_items[i].identifier, PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "id_types", rna_enum_id_type_filter_items[i].flag);
RNA_def_property_ui_text(
prop, rna_enum_id_type_filter_items[i].name, rna_enum_id_type_filter_items[i].description);
RNA_def_property_ui_icon(prop, rna_enum_id_type_filter_items[i].icon, 0);
}
}
static void rna_def_asset_data(BlenderRNA *brna)
{
StructRNA *srna;
@@ -215,12 +325,52 @@ static void rna_def_asset_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active Tag", "Index of the tag set for editing");
}
static void rna_def_asset_handle(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "AssetHandle", "PropertyGroup");
RNA_def_struct_ui_text(srna, "Asset Handle", "Reference to some asset");
prop = RNA_def_property(srna, "file_data", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_struct_type(prop, "FileSelectEntry");
RNA_def_property_pointer_funcs(
prop, "rna_AssetHandle_file_data_get", "rna_AssetHandle_file_data_set", NULL, NULL);
RNA_def_property_ui_text(prop, "File Entry", "File data used to refer to the asset");
}
static void rna_def_asset_library_reference(BlenderRNA *brna)
{
StructRNA *srna = RNA_def_struct(brna, "AssetLibraryReference", NULL);
RNA_def_struct_ui_text(
srna, "Asset Library Reference", "Identifier to refere to the asset library");
}
/**
* \note the UI text and updating has to be set by the caller.
*/
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set)
{
PropertyRNA *prop = RNA_def_property(srna, "active_asset_library", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, DummyRNA_NULL_items);
RNA_def_property_enum_funcs(prop, get, set, "rna_asset_library_reference_itemf");
return prop;
}
void RNA_def_asset(BlenderRNA *brna)
{
RNA_define_animate_sdna(false);
rna_def_asset_tag(brna);
rna_def_asset_filter_settings(brna);
rna_def_asset_data(brna);
rna_def_asset_library_reference(brna);
rna_def_asset_handle(brna);
RNA_define_animate_sdna(true);
}

View File

@@ -30,6 +30,7 @@
#define RNA_MAGIC ((int)~0)
struct AssetLibraryReference;
struct FreestyleSettings;
struct ID;
struct IDOverrideLibrary;
@@ -266,6 +267,16 @@ void rna_def_mtex_common(struct BlenderRNA *brna,
void rna_def_texpaint_slots(struct BlenderRNA *brna, struct StructRNA *srna);
void rna_def_view_layer_common(struct BlenderRNA *brna, struct StructRNA *srna, const bool scene);
PropertyRNA *rna_def_asset_library_reference_common(struct StructRNA *srna,
const char *get,
const char *set);
int rna_asset_library_reference_get(const struct AssetLibraryReference *library);
void rna_asset_library_reference_set(struct AssetLibraryReference *library, int value);
const EnumPropertyItem *rna_asset_library_reference_itemf(struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
void rna_def_actionbone_group_common(struct StructRNA *srna,
int update_flag,
const char *update_cb);

View File

@@ -128,6 +128,11 @@ static void rna_def_palettecolors(BlenderRNA *brna, PropertyRNA *cprop)
prop, "rna_Palette_active_color_get", "rna_Palette_active_color_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Palette Color", "");
/* XXX just for testing. */
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "active_color");
RNA_def_property_ui_text(prop, "Active Palette Color Index", "");
}
static void rna_def_palettecolor(BlenderRNA *brna)

View File

@@ -504,6 +504,7 @@ static const EnumPropertyItem rna_enum_curve_display_handle_items[] = {
#ifdef RNA_RUNTIME
# include "DNA_anim_types.h"
# include "DNA_asset_types.h"
# include "DNA_scene_types.h"
# include "DNA_screen_types.h"
# include "DNA_userdef_types.h"
@@ -2542,6 +2543,8 @@ static PointerRNA rna_FileSelectParams_filter_id_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_FileSelectIDFilter, ptr->data);
}
/* TODO use rna_def_asset_library_reference_common() */
static int rna_FileAssetSelectParams_asset_library_get(PointerRNA *ptr)
{
FileAssetSelectParams *params = ptr->data;
@@ -2549,7 +2552,7 @@ static int rna_FileAssetSelectParams_asset_library_get(PointerRNA *ptr)
BLI_assert(ptr->type == &RNA_FileAssetSelectParams);
/* Simple case: Predefined repo, just set the value. */
if (params->asset_library.type < FILE_ASSET_LIBRARY_CUSTOM) {
if (params->asset_library.type < ASSET_LIBRARY_CUSTOM) {
return params->asset_library.type;
}
@@ -2558,11 +2561,11 @@ static int rna_FileAssetSelectParams_asset_library_get(PointerRNA *ptr)
const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
&U, params->asset_library.custom_library_index);
if (user_library) {
return FILE_ASSET_LIBRARY_CUSTOM + params->asset_library.custom_library_index;
return ASSET_LIBRARY_CUSTOM + params->asset_library.custom_library_index;
}
BLI_assert(0);
return FILE_ASSET_LIBRARY_LOCAL;
return ASSET_LIBRARY_LOCAL;
}
static void rna_FileAssetSelectParams_asset_library_set(PointerRNA *ptr, int value)
@@ -2570,26 +2573,26 @@ static void rna_FileAssetSelectParams_asset_library_set(PointerRNA *ptr, int val
FileAssetSelectParams *params = ptr->data;
/* Simple case: Predefined repo, just set the value. */
if (value < FILE_ASSET_LIBRARY_CUSTOM) {
if (value < ASSET_LIBRARY_CUSTOM) {
params->asset_library.type = value;
params->asset_library.custom_library_index = -1;
BLI_assert(ELEM(value, FILE_ASSET_LIBRARY_LOCAL));
BLI_assert(ELEM(value, ASSET_LIBRARY_LOCAL));
return;
}
const bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
&U, value - FILE_ASSET_LIBRARY_CUSTOM);
&U, value - ASSET_LIBRARY_CUSTOM);
/* Note that the path isn't checked for validity here. If an invalid library path is used, the
* Asset Browser can give a nice hint on what's wrong. */
const bool is_valid = (user_library->name[0] && user_library->path[0]);
if (!user_library) {
params->asset_library.type = FILE_ASSET_LIBRARY_LOCAL;
params->asset_library.type = ASSET_LIBRARY_LOCAL;
params->asset_library.custom_library_index = -1;
}
else if (user_library && is_valid) {
params->asset_library.custom_library_index = value - FILE_ASSET_LIBRARY_CUSTOM;
params->asset_library.type = FILE_ASSET_LIBRARY_CUSTOM;
params->asset_library.custom_library_index = value - ASSET_LIBRARY_CUSTOM;
params->asset_library.type = ASSET_LIBRARY_CUSTOM;
}
}
@@ -2598,8 +2601,8 @@ static const EnumPropertyItem *rna_FileAssetSelectParams_asset_library_itemf(
{
const EnumPropertyItem predefined_items[] = {
/* For the future. */
// {FILE_ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
{FILE_ASSET_LIBRARY_LOCAL,
// {ASSET_REPO_BUNDLED, "BUNDLED", 0, "Bundled", "Show the default user assets"},
{ASSET_LIBRARY_LOCAL,
"LOCAL",
ICON_BLENDER,
"Current File",
@@ -2627,7 +2630,7 @@ static const EnumPropertyItem *rna_FileAssetSelectParams_asset_library_itemf(
}
/* Use library path as description, it's a nice hint for users. */
EnumPropertyItem tmp = {FILE_ASSET_LIBRARY_CUSTOM + i,
EnumPropertyItem tmp = {ASSET_LIBRARY_CUSTOM + i,
user_library->name,
ICON_NONE,
user_library->name,
@@ -2955,7 +2958,7 @@ static void rna_FileBrowser_FSMenu_active_range(PointerRNA *UNUSED(ptr),
static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *ptr)
{
ScrArea *area = rna_area_from_space(ptr);
ED_file_change_dir_ex(C, (bScreen *)ptr->owner_id, area);
ED_file_change_dir_ex(C, area);
}
static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr)
@@ -3107,6 +3110,45 @@ static const EnumPropertyItem dt_uv_items[] = {
{0, NULL, 0, NULL, NULL},
};
static struct IDFilterEnumPropertyItem rna_enum_space_file_id_filter_categories[] = {
/* Categories */
{FILTER_ID_SCE, "category_scene", ICON_SCENE_DATA, "Scenes", "Show scenes"},
{FILTER_ID_AC, "category_animation", ICON_ANIM_DATA, "Animations", "Show animation data"},
{FILTER_ID_OB | FILTER_ID_GR,
"category_object",
ICON_OUTLINER_COLLECTION,
"Objects & Collections",
"Show objects and collections"},
{FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME | FILTER_ID_HA |
FILTER_ID_PT | FILTER_ID_VO,
"category_geometry",
ICON_NODETREE,
"Geometry",
"Show meshes, curves, lattice, armatures and metaballs data"},
{FILTER_ID_LS | FILTER_ID_MA | FILTER_ID_NT | FILTER_ID_TE,
"category_shading",
ICON_MATERIAL_DATA,
"Shading",
"Show materials, nodetrees, textures and Freestyle's linestyles"},
{FILTER_ID_IM | FILTER_ID_MC | FILTER_ID_MSK | FILTER_ID_SO,
"category_image",
ICON_IMAGE_DATA,
"Images & Sounds",
"Show images, movie clips, sounds and masks"},
{FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_LP | FILTER_ID_SPK | FILTER_ID_WO,
"category_environment",
ICON_WORLD_DATA,
"Environment",
"Show worlds, lights, cameras and speakers"},
{FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT |
FILTER_ID_VF | FILTER_ID_CF | FILTER_ID_WS,
"category_misc",
ICON_GREASEPENCIL,
"Miscellaneous",
"Show other data types"},
{0, NULL, 0, NULL, NULL},
};
static void rna_def_space_generic_show_region_toggles(StructRNA *srna, int region_type_mask)
{
PropertyRNA *prop;
@@ -4788,6 +4830,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
}
/* Nested Structs */
prop = RNA_def_property(srna, "shading", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "View3DShading");
@@ -6031,142 +6074,6 @@ static void rna_def_space_console(BlenderRNA *brna)
/* Filter for datablock types in link/append. */
static void rna_def_fileselect_idfilter(BlenderRNA *brna)
{
struct IDFilterBoolean {
/* 64 bit, so we can't use bitflag enum. */
const uint64_t flag;
const char *identifier;
const int icon;
const char *name;
const char *description;
};
static const struct IDFilterBoolean booleans[] = {
/* Datablocks */
{FILTER_ID_AC, "filter_action", ICON_ANIM_DATA, "Actions", "Show Action data-blocks"},
{FILTER_ID_AR,
"filter_armature",
ICON_ARMATURE_DATA,
"Armatures",
"Show Armature data-blocks"},
{FILTER_ID_BR, "filter_brush", ICON_BRUSH_DATA, "Brushes", "Show Brushes data-blocks"},
{FILTER_ID_CA, "filter_camera", ICON_CAMERA_DATA, "Cameras", "Show Camera data-blocks"},
{FILTER_ID_CF, "filter_cachefile", ICON_FILE, "Cache Files", "Show Cache File data-blocks"},
{FILTER_ID_CU, "filter_curve", ICON_CURVE_DATA, "Curves", "Show Curve data-blocks"},
{FILTER_ID_GD,
"filter_grease_pencil",
ICON_GREASEPENCIL,
"Grease Pencil",
"Show Grease pencil data-blocks"},
{FILTER_ID_GR,
"filter_group",
ICON_OUTLINER_COLLECTION,
"Collections",
"Show Collection data-blocks"},
{FILTER_ID_HA, "filter_hair", ICON_HAIR_DATA, "Hairs", "Show/hide Hair data-blocks"},
{FILTER_ID_IM, "filter_image", ICON_IMAGE_DATA, "Images", "Show Image data-blocks"},
{FILTER_ID_LA, "filter_light", ICON_LIGHT_DATA, "Lights", "Show Light data-blocks"},
{FILTER_ID_LP,
"filter_light_probe",
ICON_OUTLINER_DATA_LIGHTPROBE,
"Light Probes",
"Show Light Probe data-blocks"},
{FILTER_ID_LS,
"filter_linestyle",
ICON_LINE_DATA,
"Freestyle Linestyles",
"Show Freestyle's Line Style data-blocks"},
{FILTER_ID_LT, "filter_lattice", ICON_LATTICE_DATA, "Lattices", "Show Lattice data-blocks"},
{FILTER_ID_MA,
"filter_material",
ICON_MATERIAL_DATA,
"Materials",
"Show Material data-blocks"},
{FILTER_ID_MB, "filter_metaball", ICON_META_DATA, "Metaballs", "Show Metaball data-blocks"},
{FILTER_ID_MC,
"filter_movie_clip",
ICON_TRACKER_DATA,
"Movie Clips",
"Show Movie Clip data-blocks"},
{FILTER_ID_ME, "filter_mesh", ICON_MESH_DATA, "Meshes", "Show Mesh data-blocks"},
{FILTER_ID_MSK, "filter_mask", ICON_MOD_MASK, "Masks", "Show Mask data-blocks"},
{FILTER_ID_NT,
"filter_node_tree",
ICON_NODETREE,
"Node Trees",
"Show Node Tree data-blocks"},
{FILTER_ID_OB, "filter_object", ICON_OBJECT_DATA, "Objects", "Show Object data-blocks"},
{FILTER_ID_PA,
"filter_particle_settings",
ICON_PARTICLE_DATA,
"Particles Settings",
"Show Particle Settings data-blocks"},
{FILTER_ID_PAL, "filter_palette", ICON_COLOR, "Palettes", "Show Palette data-blocks"},
{FILTER_ID_PC,
"filter_paint_curve",
ICON_CURVE_BEZCURVE,
"Paint Curves",
"Show Paint Curve data-blocks"},
{FILTER_ID_PT,
"filter_pointcloud",
ICON_POINTCLOUD_DATA,
"Point Clouds",
"Show/hide Point Cloud data-blocks"},
{FILTER_ID_SCE, "filter_scene", ICON_SCENE_DATA, "Scenes", "Show Scene data-blocks"},
{FILTER_ID_SIM,
"filter_simulation",
ICON_PHYSICS,
"Simulations",
"Show Simulation data-blocks"}, /* TODO: Use correct icon. */
{FILTER_ID_SPK, "filter_speaker", ICON_SPEAKER, "Speakers", "Show Speaker data-blocks"},
{FILTER_ID_SO, "filter_sound", ICON_SOUND, "Sounds", "Show Sound data-blocks"},
{FILTER_ID_TE, "filter_texture", ICON_TEXTURE_DATA, "Textures", "Show Texture data-blocks"},
{FILTER_ID_TXT, "filter_text", ICON_TEXT, "Texts", "Show Text data-blocks"},
{FILTER_ID_VF, "filter_font", ICON_FONT_DATA, "Fonts", "Show Font data-blocks"},
{FILTER_ID_VO, "filter_volume", ICON_VOLUME_DATA, "Volumes", "Show/hide Volume data-blocks"},
{FILTER_ID_WO, "filter_world", ICON_WORLD_DATA, "Worlds", "Show World data-blocks"},
{FILTER_ID_WS,
"filter_work_space",
ICON_WORKSPACE,
"Workspaces",
"Show workspace data-blocks"},
/* Categories */
{FILTER_ID_SCE, "category_scene", ICON_SCENE_DATA, "Scenes", "Show scenes"},
{FILTER_ID_AC, "category_animation", ICON_ANIM_DATA, "Animations", "Show animation data"},
{FILTER_ID_OB | FILTER_ID_GR,
"category_object",
ICON_OUTLINER_COLLECTION,
"Objects & Collections",
"Show objects and collections"},
{FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME | FILTER_ID_HA |
FILTER_ID_PT | FILTER_ID_VO,
"category_geometry",
ICON_NODETREE,
"Geometry",
"Show meshes, curves, lattice, armatures and metaballs data"},
{FILTER_ID_LS | FILTER_ID_MA | FILTER_ID_NT | FILTER_ID_TE,
"category_shading",
ICON_MATERIAL_DATA,
"Shading",
"Show materials, nodetrees, textures and Freestyle's linestyles"},
{FILTER_ID_IM | FILTER_ID_MC | FILTER_ID_MSK | FILTER_ID_SO,
"category_image",
ICON_IMAGE_DATA,
"Images & Sounds",
"Show images, movie clips, sounds and masks"},
{FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_LP | FILTER_ID_SPK | FILTER_ID_WO,
"category_environment",
ICON_WORLD_DATA,
"Environment",
"Show worlds, lights, cameras and speakers"},
{FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT |
FILTER_ID_VF | FILTER_ID_CF | FILTER_ID_WS,
"category_misc",
ICON_GREASEPENCIL,
"Miscellaneous",
"Show other data types"},
{0, NULL, 0, NULL, NULL}};
StructRNA *srna = RNA_def_struct(brna, "FileSelectIDFilter", NULL);
RNA_def_struct_sdna(srna, "FileSelectParams");
@@ -6174,12 +6081,23 @@ static void rna_def_fileselect_idfilter(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "File Select ID Filter", "Which ID types to show/hide, when browsing a library");
for (int i = 0; booleans[i].identifier; i++) {
PropertyRNA *prop = RNA_def_property(srna, booleans[i].identifier, PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter_id", booleans[i].flag);
RNA_def_property_ui_text(prop, booleans[i].name, booleans[i].description);
RNA_def_property_ui_icon(prop, booleans[i].icon, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
const struct IDFilterEnumPropertyItem *individual_ids_and_categories[] = {
rna_enum_id_type_filter_items,
rna_enum_space_file_id_filter_categories,
NULL,
};
for (uint i = 0; individual_ids_and_categories[i]; i++) {
for (int j = 0; individual_ids_and_categories[i][j].identifier; j++) {
PropertyRNA *prop = RNA_def_property(
srna, individual_ids_and_categories[i][j].identifier, PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
prop, NULL, "filter_id", individual_ids_and_categories[i][j].flag);
RNA_def_property_ui_text(prop,
individual_ids_and_categories[i][j].name,
individual_ids_and_categories[i][j].description);
RNA_def_property_ui_icon(prop, individual_ids_and_categories[i][j].icon, 0);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
}
}
}
@@ -6435,7 +6353,7 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
/* XXX copied from rna_def_fileselect_idfilter. */
/* XXX copied from rna_enum_id_type_filter_items. */
static const EnumPropertyItem asset_category_items[] = {
{FILTER_ID_SCE, "SCENES", ICON_SCENE_DATA, "Scenes", "Show scenes"},
{FILTER_ID_AC, "ANIMATIONS", ICON_ANIM_DATA, "Animations", "Show animation data"},

View File

@@ -50,6 +50,8 @@ const EnumPropertyItem rna_enum_icon_items[] = {
#ifdef RNA_RUNTIME
# include "DNA_asset_types.h"
const char *rna_translate_ui_text(
const char *text, const char *text_ctxt, StructRNA *type, PropertyRNA *prop, bool translate)
{
@@ -568,6 +570,65 @@ static void rna_uiTemplateEventFromKeymapItem(
uiTemplateEventFromKeymapItem(layout, name, kmi, true);
}
static void rna_uiTemplateAssetView(uiLayout *layout,
bContext *C,
const char *list_id,
PointerRNA *asset_library_dataptr,
const char *asset_library_propname,
PointerRNA *assets_dataptr,
const char *assets_propname,
PointerRNA *active_dataptr,
const char *active_propname,
int filter_id_types,
const char *activate_opname,
const char *drag_opname)
{
AssetFilterSettings filter_settings = {
.id_types = filter_id_types ? filter_id_types : FILTER_ID_ALL,
};
uiTemplateAssetView(layout,
C,
list_id,
asset_library_dataptr,
asset_library_propname,
assets_dataptr,
assets_propname,
active_dataptr,
active_propname,
&filter_settings,
activate_opname,
drag_opname);
}
/**
* XXX Remove filter items that require more than 32 bits for storage. RNA enums don't support
* that currently.
*/
static const EnumPropertyItem *rna_uiTemplateAssetView_filter_id_types_itemf(
bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem *items = NULL;
int totitem = 0;
for (int i = 0; rna_enum_id_type_filter_items[i].identifier; i++) {
if (rna_enum_id_type_filter_items[i].flag > (1ULL << 31)) {
continue;
}
EnumPropertyItem tmp = {0, "", 0, "", ""};
tmp.value = rna_enum_id_type_filter_items[i].flag;
tmp.identifier = rna_enum_id_type_filter_items[i].identifier;
tmp.icon = rna_enum_id_type_filter_items[i].icon;
tmp.name = rna_enum_id_type_filter_items[i].name;
tmp.description = rna_enum_id_type_filter_items[i].description;
RNA_enum_item_add(&items, &totitem, &tmp);
}
RNA_enum_item_end(&items, &totitem);
*r_free = true;
return items;
}
static uiLayout *rna_uiLayoutRowWithHeading(
uiLayout *layout, bool align, const char *heading, const char *heading_ctxt, bool translate)
{
@@ -1677,6 +1738,65 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_property_ui_text(parm, "Item", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
api_ui_item_common_text(func);
func = RNA_def_function(srna, "template_asset_view", "rna_uiTemplateAssetView");
RNA_def_function_ui_description(func, "Item. A scrollable list of assets in a grid view");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_string(func,
"list_id",
NULL,
0,
"",
"Identifier of this asset view. Necessary to tell apart different asset "
"views and to idenify an asset view read from a .blend");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func,
"asset_library_dataptr",
"AnyType",
"",
"Data from which to take the active asset library property");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(
func, "asset_library_propname", NULL, 0, "", "Identifier of the asset library property");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(
func, "assets_dataptr", "AnyType", "", "Data from which to take the asset list property");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(
func, "assets_propname", NULL, 0, "", "Identifier of the asset list property");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func,
"active_dataptr",
"AnyType",
"",
"Data from which to take the integer property, index of the active item");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(
func,
"active_propname",
NULL,
0,
"",
"Identifier of the integer property in active_data, index of the active item");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_property(func, "filter_id_types", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, DummyRNA_NULL_items);
RNA_def_property_enum_funcs(parm, NULL, NULL, "rna_uiTemplateAssetView_filter_id_types_itemf");
RNA_def_property_flag(parm, PROP_ENUM_FLAG);
RNA_def_string(func,
"activate_operator",
NULL,
0,
"",
"Name of a custom operator to invoke when activating an item");
RNA_def_string(func,
"drag_operator",
NULL,
0,
"",
"Name of a custom operator to invoke when starting to drag an item. Never "
"invoked together with the `active_operator` (if set), it's either the drag or "
"the activate one");
}
#endif

View File

@@ -107,6 +107,18 @@ static void rna_WorkSpace_owner_ids_clear(WorkSpace *workspace)
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, workspace);
}
static int rna_WorkSpace_active_asset_library_get(PointerRNA *ptr)
{
const WorkSpace *workspace = ptr->data;
return rna_asset_library_reference_get(&workspace->active_asset_library);
}
static void rna_WorkSpace_active_asset_library_set(PointerRNA *ptr, int value)
{
WorkSpace *workspace = ptr->data;
rna_asset_library_reference_set(&workspace->active_asset_library, value);
}
static bToolRef *rna_WorkSpace_tools_from_tkey(WorkSpace *workspace,
const bToolKey *tkey,
bool create)
@@ -407,6 +419,14 @@ static void rna_def_workspace(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use UI Tags", "Filter the UI by tags");
RNA_def_property_update(prop, 0, "rna_window_update_all");
prop = rna_def_asset_library_reference_common(
srna, "rna_WorkSpace_active_asset_library_get", "rna_WorkSpace_active_asset_library_set");
RNA_def_property_ui_text(prop,
"Asset Library",
"Active asset library to show in the UI, not used by the Asset Browser "
"(which has its own active asset library)");
RNA_def_property_update(prop, NC_ASSET | ND_ASSET_LIST_READING, NULL);
RNA_api_workspace(srna);
}

View File

@@ -255,6 +255,8 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}

View File

@@ -434,6 +434,12 @@ typedef struct wmNotifier {
#define ND_SPACE_FILE_PREVIEW (21 << 16)
#define ND_SPACE_SPREADSHEET (22 << 16)
/* NC_ASSET */
/* Denotes that the AssetList is done reading some previews. NOT that the preview generation of
* assets is done. */
#define ND_ASSET_LIST_PREVIEW (1 << 16)
#define ND_ASSET_LIST_READING (2 << 16)
/* subtype, 256 entries too */
#define NOTE_SUBTYPE 0x0000FF00

View File

@@ -61,6 +61,7 @@
#include "BLT_translation.h"
#include "ED_asset.h"
#include "ED_fileselect.h"
#include "ED_info.h"
#include "ED_screen.h"
@@ -326,6 +327,7 @@ void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
}
}
}
ED_assetlist_storage_id_remap(old_id, new_id);
wmWindowManager *wm = bmain->wm.first;
if (wm && wm->message_bus) {

View File

@@ -109,6 +109,7 @@
#include "ED_anim_api.h"
#include "ED_armature.h"
#include "ED_asset.h"
#include "ED_gpencil.h"
#include "ED_keyframes_edit.h"
#include "ED_keyframing.h"
@@ -566,6 +567,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
RE_engines_exit();
ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */
ED_assetlist_storage_exit();
if (wm) {
/* Before BKE_blender_free! - since the ListBases get freed there. */