1
1

Compare commits

...

141 Commits

Author SHA1 Message Date
30bebec477 Intensity and color are now adjusted upon import to get correct values 2014-08-09 20:43:37 +02:00
Dalai Felinto
1f9657ecc7 Style and related cleanups 2014-08-08 11:09:36 +02:00
704d710ddc remove unused import 2014-08-08 05:52:13 +10:00
315d00f76b Merge branch 'master' into pie-menus 2014-08-08 05:48:40 +10:00
f03e2bf47a remove accidental committed file 2014-08-08 05:45:13 +10:00
d42b85e2d8 Change template to an edit mode selection pie menu. 2014-08-07 17:07:57 +02:00
ec6043cd66 picky - prefer braces 2014-08-08 00:21:20 +10:00
4ce9447b08 remove rna_Space_transform_manipulators_update
Better not have settings manipulate eachother where possible,
in this case an operator could be used to manage mixing manipulator options
2014-08-08 00:21:20 +10:00
e6e5fd5475 remove rna_Space_transform_manipulators_update
Better not have settings manipulate eachother where possible,
in this case an operator could be used to manage mixing manipulator options
2014-08-08 00:09:38 +10:00
d73a57698b minor tweaks 2014-08-08 00:02:19 +10:00
c8794563f1 Correct example 2014-08-07 23:48:40 +10:00
ba4bc4c58e Merge branch 'master' into pie-menus
Conflicts:
	source/blender/editors/interface/interface_intern.h
2014-08-07 23:20:57 +10:00
8323d88ef8 According to final verdict:
* Remove sticky keys
* Remove all pie menus

Left some icon changes to some properties and some reordering of enums
to look better for pie menus (Might go away in a later iteration).

Some pies will make it back as an Add-On (will be a separate commit)
2014-08-07 11:49:29 +02:00
2b67bf7510 Bring back extrude menu (was removed on earlier iteration of the code,
no need to have this anymore)
2014-08-03 16:52:59 +02:00
863fd8a4fc rename ui_pie -> ui_(but/block)_pie 2014-08-03 04:14:53 +10:00
8e12efb431 set UI_RADIAL_NONE to -1 so we can use the enum to undex arrays 2014-08-03 02:28:31 +10:00
485f9b88db minor formatting 2014-08-03 02:17:43 +10:00
c3b87fced2 Minor edits to draw_disk_shaded 2014-08-03 02:15:27 +10:00
4e52fac147 replace switches with lookups 2014-08-03 02:14:15 +10:00
20cb5f7a3e Hide Center Points option if not in object mode 2014-08-02 18:11:07 +02:00
5b5c8afb60 Attempt to support retina also cleanup on identifier 2014-08-02 17:26:54 +02:00
4fe223ab0e Simplify some 2d vector use 2014-08-02 04:29:37 +10:00
b7ad6b4437 Minor changes, sync with master 2014-08-02 04:12:47 +10:00
567e062102 Merge branch 'master' into pie-menus 2014-08-02 03:13:58 +10:00
ed62c38730 Final fix for X11 weirdness.
Fortunately the extra keypress that comes after keyrelease has a time
signature less or equal than the last keyrelease of the same type, so
the included code will enable us to detect and reject such keypresses
safely and without many hacks.
2014-08-01 17:51:30 +02:00
b8801997b2 Revert "X11 code that disables autorepeat."
This reverts commit b892c8a452.

It's difficult to count exit and entrance for pie menus, since it can be done
in many different ways and there are cases where defocusing from blender window
can make the system confused. This is not so serious in itself but this disables
autocomplete -everywhere- on the system and it really is troubling when
it doesn't work. Even navigation on webpages by holding directional keys
breaks. We will use dufferent code to detect autorepeats here.
2014-08-01 12:11:56 +02:00
b892c8a452 X11 code that disables autorepeat.
This makes it so as long as there is a pie menu active, autorepeat is
off. It is meant to cater for support for multiple coexisting pies in
the future too but no tests can be really made here yet.
2014-07-31 18:38:06 +02:00
664dc55305 Remove force click argument, now pies detect click style automatically 2014-07-31 18:00:15 +02:00
0a3f279855 Remove X11 hack.
Cannot reproduce original issue on studio pc anymore, will try on other
pcs too to make sure it is unneeded now (maybe issue was fixed upstream
or pie interaction system now hides this better.)
2014-07-31 17:38:08 +02:00
f52cdcf97c Merge branch 'master' into pie-menus 2014-07-31 17:08:35 +02:00
0ae03b6fa1 minor edits - sync with master
also use ***_menu_pie for operator names
2014-07-31 23:13:18 +10:00
eb20ebe5c2 Change blender subversion correctly for pie menus. Also no need for
conditionals here.
2014-07-31 11:05:34 +02:00
d60804b72d Fixes:
* Space sticky did not call search menu
* Cancelling and confirming with no active button would respawn the pie
menu immediately in drag style interaction
* Area now covers the whole screen, collision with pie buttons is done
always.
2014-07-30 19:01:48 +02:00
e38cafbe51 Fix issue with navigation pie/search menu 2014-07-30 18:20:02 +02:00
dcf5c52e44 Change the enum fetching code to be order independent.
This is done by checking each item in a dynamic enum for existence.

This can result in n^2 cost in worst case (for 8 items about 64 steps)
but since this is done once on initialization and makes the system more
robust, better prefer it.
2014-07-30 17:20:26 +02:00
b844da7750 Code cleanup, move function to correct header 2014-07-30 16:29:54 +02:00
5eae52ae96 Quiet double promotion warnings 2014-07-31 00:00:18 +10:00
759d772408 Merge branch 'master' into pie-menus 2014-07-30 15:51:35 +02:00
517d28ea26 Change rename to one proposed by Campbell 2014-07-30 15:47:56 +02:00
90906db4fd Address Dalai's concerns 2014-07-30 15:37:05 +02:00
0f34796ed9 * Move view pie to sticky space (to avoid clashes with many add-ons)
* Fix naming
2014-07-30 14:57:20 +02:00
6c4bab22db add ui_radial_dir_to_num lookup to avoid long switch () 2014-07-30 22:40:36 +10:00
ba3acdeba0 Fix tooltips for numpad numbering 2014-07-30 13:53:23 +02:00
7a4cec4c22 use macro for numpad direction & deduplicate 2014-07-30 21:31:39 +10:00
c18e168c09 Numbers appear on pie menu items, showing which number corresponds to
them
2014-07-30 13:24:57 +02:00
9643f78cfe Pie menus:
Numeric input support.

After a bit of thought, I chose a scheme based on directions, starting
from top and going clockwise. We count empty positions too, so each
number from 1-8 is bound to a specific direction. There are no text
indicators on the menu items yet for the numbers.
2014-07-30 13:01:45 +02:00
ba918f2f3d Clamp pies against window borders only, not screen borders.
Added after Dalai's suggestion. Initially i was against this but
clamping against editor area makes pies feel cramped indeed and more
often than not causes a shift in the spawned menu position.

It's not 100% certain still we'll keep this, but having a nice commit
with the feature is not bad either.
2014-07-30 12:25:56 +02:00
Dalai Felinto
f6fc2f5991 small cleanup against mater to avoid conflict when merge-testing with multiview 2014-07-29 17:49:28 -03:00
0b064ce2d4 Only modify outline of selected pie items. 2014-07-29 17:50:21 +02:00
da844af3a0 Proper fix for previous fix (tm) 2014-07-29 17:42:07 +02:00
4a17f1bd62 Manipulator property toggle did not work. Add toggle operator instead 2014-07-29 16:19:49 +02:00
65df2781fd Proper fix of tooltips not exiting 2014-07-29 15:46:41 +02:00
ea3a11fa69 Fix tooltip sticking to button 2014-07-29 15:13:02 +02:00
ab409e645d Pies:
* Fix issue with repositioned pie menus
* Reduce default animation time
2014-07-29 15:08:17 +02:00
bc11096db4 Change to pie iinteraction:
After discussion with Campbell use combination of drag/click style
interaction and ommit option:

If initial button is released while the menu is still within the
threshold then switch to click style. If not then do regular selection.
2014-07-29 14:36:03 +02:00
336ca4e398 Use UI_DPI_WINDOW_FAC define 2014-07-29 21:31:28 +10:00
0ed8058347 Pie radius scales correctly with DPI 2014-07-29 12:53:22 +02:00
06278f03dd Bring back good ole regular menu here so people can use number
accelerators as they are used to.
2014-07-29 12:48:24 +02:00
5fd10b15a6 Revert "Pie Menus:"
This reverts commit 0d92435a71.

The reason is that the operator needs greater changes for this to work
correctly, may even better to have a new operator for this operation
2014-07-29 12:12:21 +02:00
0d92435a71 Pie Menus:
* Editmesh selection pie can spawn combinations.

* Remove extraneous flag from operators.
2014-07-29 11:44:27 +02:00
c3f8a08fe4 Add simple pie menu template 2014-07-28 20:22:41 +02:00
b5ce99ddf7 Calculate correct segment when offsetting the pie menu. 2014-07-28 17:13:44 +02:00
8359fa245e Pie menus:
* Rename Align -> Center points in pivot menu
* Turn Manipulator on when a manipulator is selected in manipulator pie
2014-07-28 16:56:07 +02:00
cae1d7dab0 Merge branch 'master' into pie-menus 2014-07-28 16:25:10 +02:00
09977b40c4 Pie Menus:
* Do not recenter items for animation if animation timeout is zero. Avoids
flickering at start of animation

* Initialize pies with invalid direction
2014-07-28 16:19:00 +02:00
45bff7af39 New pies:
* Snapping sticky pie (comma key)
* Pivot sticky pie (period key)
2014-07-28 14:46:25 +02:00
b192c1da74 Expose pie animation timeo to user preferences. 2014-07-28 14:00:58 +02:00
69c0e5f175 Fix some remaining issues with the shade pie menu 2014-07-28 13:21:20 +02:00
6ac1a646ec Pies:
* Remove testing pie menu
* Fix enums with missing items not using radial layout
* Fix recentering on bounds not working anymore
* View pie was missing material mode in blender internal.
2014-07-28 13:11:11 +02:00
87799657fe Transform manipulator sticky pie menu (ctrl-space) 2014-07-25 22:03:15 +02:00
84b7035227 Pie menus:
* Click and close for drag style pie menus to work better
* Pie menus now handle letter events for quick selecting items
* Double buttons do not enforce click style (left the code in just in
case, but deactivated the argument for now)
2014-07-25 15:06:15 +02:00
9241221ff1 Pie Menus:
* Fix flickering in pie menus.
* Start from center position initially.
* Fix memory over-cleanup.
* All stroke selections in paint systems use pie menus.
2014-07-24 17:20:18 +02:00
37e9ab73e1 Merge branch 'master' into pie-menus
Conflicts:
	source/blender/editors/interface/interface_handlers.c
	source/blender/editors/sculpt_paint/paint_ops.c
	source/blender/editors/space_api/spacetypes.c
2014-07-24 16:30:27 +02:00
17d35f9e80 Merge branch 'master' into pie-menus
Conflicts:
	source/blender/editors/interface/interface.c
	source/blender/windowmanager/intern/wm_event_system.c
2014-07-20 16:32:16 +10:00
5529e51a21 Extrude operator sticky key pie:
* Press once to extrude along normals
* Hold to spawn pie with options
* Removed the Alt-E shortcut.
2014-07-08 22:57:50 +03:00
42143ce873 Add internal operator for enum pies supporting paths.
Used in proportinal editing in edit mode currently.

Also moved all macro definitions after python initialization to enable
referencing of python defined operators in all macros.
2014-07-08 22:30:23 +03:00
02c7aa4455 Proper implementation of click style override:
Guide: This is added for double key combinations. In these situations,
holding the second key can be taxing and stretching for the hand.

Forcing a click style here is better. Ctrl-Tab for edit mode selection
uses this override currently.
2014-07-08 19:33:06 +03:00
53a1708860 Separate property for viewport shade pies.
This is fine tuned for using with pie menus, where solid/wire mode
is given the most important west/east positions.

There were two possibilities with supporting custom pie enums for an
existing property. One is to add an extra function that dynamically
fills the pie items to fit a pie scheme. The other is make a separate
python property. I feel this is the correct way because it does not
burden all enum properties with extra function storage and it does not
always need to be dynamic either.

Also cleanup minor debug line
2014-07-08 18:14:56 +03:00
8df8824f3a Change enum behaviour:
Enums now get completely expanded and any items not present in a dynamic
enum are filled by separators. This makes it possible to have
predictable positions even if some items are missing.

The iteration code expects that the dynamic and initial enum lists have
the same ordering of items, which is not unreasonable.
2014-07-08 17:50:54 +03:00
838c692b93 Change user preference for drag/click style.
Use explicit chooser instead of timeout.
2014-07-08 14:32:18 +03:00
97ab366e44 Merge branch 'master' into pie-menus 2014-07-08 00:00:49 +03:00
fba08b9092 Pie Menus:
Add code to force a certain pie menu to be in hold style interaction
mode always. This is useful for tap/hold operator/pie menus

Move operator enum operator in C, this allows us to fire it up
internally without resorting to operators.

Deleted python code for this since it's not used and it's really easy to
code. May do if scripters want though.
2014-06-30 20:57:07 +03:00
d00f63627b Tweaks:
* Increase the animation timeout slightly
* Remove separator from shade menu.

Custom pies are really OK, but enums are somewhat problematic because
we don't have a way yet to explicitly set the ordering and positions
while expanding them. This is for immediate todo.
2014-06-30 18:49:39 +03:00
921b8d6907 Fix issue on X11 where fake keyrelease events can fire.
This could happen but was not too noticable before, however on pie menus
where holding a key and releasing is common, such double events could
fire the pie menu again or even call the tap operator on tap/hold
operator/pies, which was especially noticable on object mode selection.
2014-06-30 18:19:10 +03:00
a69ab5509a Merge branch 'master' into pie-menus 2014-06-30 14:58:35 +03:00
47c2250a7e Do not display pie menu items with embossing. 2014-06-30 04:49:46 +03:00
eade6e7b66 Animated pie menus!
Nuff said :)
2014-06-30 01:26:09 +03:00
af8d5d2b24 Make the pie menu macro definition into a function.
Also set Z key as hybrid toggle/hold type menu.
To make this work, the macro definition must be set after python
initialization because we use operators defined in python (maybe it's
worth doing that for all macros?)
2014-06-29 22:11:21 +03:00
285bea9949 Pies:
* Make position function simpler
* Fix some tooltips
2014-06-29 21:05:56 +03:00
3a969f52ee Fix blenderplayer compilation, fire timer for pie timeout in 100ths of
second.
2014-06-27 21:16:21 +03:00
795592dc90 Pies:
* Add pretty icons to Q menu

* Add an operator to sculpt Q pie for testing.
2014-06-27 04:26:06 +03:00
83d713c606 Pies:
* Modify timed pie macro with own timeout property.
* Times are now counted in 100ths of second, gives more needed
precision.
* Add whole event argument to pie creation so we can spawn at custom
initial position
* Escape key also exits pie menus now.
2014-06-27 03:42:48 +03:00
4c84e89761 Merge branch 'refs/heads/master' into pie-menus 2014-06-27 02:24:05 +03:00
a613ef67df Proof of concept pie interaction:
Press for calling operator, hold to spawn pie menu.

Test on object mode operator, pressing TAB toggles to edit mode, keeping
TAB pressed more that the drag timeout spawns a pie menu.

Still needs a way to enforce the menu to not listen for further drag
timeouts but looks like the concept holds.

This is implemented using the previous operator,
WM_OT_call_pie_menu_timer, in a macro. When the calling button is
pressed too long, the operator is cancelled (thus cancelling the macro)
but spawning a pie menu before that. If the timeout is not reached and
a key release event is detected, the operator finishes and the macro
continues, calling the next operator instead (object mode set, in our
case).
2014-06-24 23:56:21 +03:00
e748662785 Fix minor issue, pie menu is set as cancelled only for hold/release
style menus.
2014-06-24 23:32:59 +03:00
dc77502804 Experimental:
Add timer wm operator that spawns pie menus after a certain time.

For now this timeout is the same as the drag timeout, should probably be
a separate option
2014-06-24 23:29:40 +03:00
6c9216fc49 Tweaks to the central pie menu widget:
Adopt a disc based design, also serves to better identify the threshold
value for a valid selection and is now fully themeable.
2014-06-24 22:27:44 +03:00
6a27e8ed0b Merge branch 'master' into pie-menus 2014-06-24 20:22:08 +03:00
8eb5aa1c35 Fix recursive menus respawning on selection
Fix here is a bit hacky, we do not draw the menu and we simply await for
key release to stop the handler, or else the pie menu gets respawned
immediately.
2014-06-20 04:11:43 +03:00
3a7899c5eb Allow recursive menus in pies.
By returning the handler function to the general menu recursive section.
we can handle any menus that exist in the pie pieces. For now the
drag/release style pies do not work very well with this (menu is
respawned as soon as we select something in the child menu) but I hope
this can be improved further.
2014-06-20 03:58:57 +03:00
cb2aca5833 Add icons for a few items in the menus.
Change edit mode selection to pie menu
2014-06-17 02:58:53 +03:00
6fbd801713 Add view and shade pie menus. 2014-06-17 02:26:53 +03:00
989bdf6748 Rename layout.pie to menu_pie 2014-06-15 16:59:36 +10:00
0c7fd1622a Minor changes and sync with master (reduce diff noise) 2014-06-15 16:53:41 +10:00
20a570f6b7 Rename WM_HANDLER_ACCEPT_DBLPRESS -> WM_HANDLER_ACCEPT_DBL_CLICK
also some minor changes for ui_centered_pie_bounds_block
2014-06-15 16:53:22 +10:00
b94eaf041f Minor changes to WM_OT_context_operator_pie_enum
- dont eval("bpy.ops. ... ")
- split the operator name and property into 2 properties.
2014-06-15 16:22:12 +10:00
a3128b0c95 Code Cleanup: style 2014-06-15 15:51:11 +10:00
74432c94f3 Merge branch 'master' into pie-menus
Conflicts:
	source/blender/editors/interface/interface.c
2014-06-15 15:37:40 +10:00
882e6de2fa Threshold value for pie menus.
Require at least a small (adjustable in user preferences) distance from
the center of the menu before a selection can be made. Default is 5
pixels.
2014-06-11 19:52:14 +03:00
25175306e3 Fixes
* pie menus with 3 items were not aligned correctly
* clipping translation can be done if one dimension of screen is large
enough.
2014-06-11 19:00:48 +03:00
6d1f76d21b Pie Menu fixes - features
* Allow setting arbitrary layouts in radial regions.  This can be
used to make nice arrangements of subareas in the pie menu. Only buttons
directly in a pie layout will use pie menu style collision detection,
any buttons in nested layouts will use regular collision detection.
Appended a test menu in Q key, sculpt mode.

* Allow aligning of buttons now to permit any aligned nested layouts to
properly align their buttons

* Operator enums will now spawn to a pie menu if the layout is a root
layout of radial type.
2014-06-11 17:31:33 +03:00
c5b7841b78 Themify pie menu colors. 2014-06-10 19:02:17 +03:00
a209b323dc Merge branch 'master' into pie-menus 2014-06-10 17:31:12 +03:00
9ad2623d0d Corrections to user preference descriptions and UI style. 2014-06-06 03:38:48 +03:00
4349505c6e Pie Menu goodies
* Support custom pie menu radius
* Recenter timeout: This feature makes it so whenever user activates the
pie menu at the edge of the current screen, the code still uses the
initial mouse position to calculate the drag direction for a certain
timeout.

The recenter and drag timeout feature were directly infuenced by the pie
menu add-on by Dan Eicher, Sean Olson and Patrick Moore. Thanks a lot!
2014-06-06 03:07:49 +03:00
8d838f02e2 Pie Menu goodies:
* Add right click cancel to pie menus.
* Add drag style timeout. If the button used to spawn the menu is
released before the time out then leftclick will be used to confirm the
menu.
2014-06-06 02:17:07 +03:00
814df8ca34 Pie menus have their own handler function now.
This is necessary because pie menus behave quite differently than
regular menus. This will allow us to tweak the behaviour accordingly
without too many spaghetti nightmares
2014-06-06 00:53:40 +03:00
bd5aa57c35 Refactor: Isolate pie menu data in own struct. 2014-06-05 21:32:26 +03:00
208d21d63f Merge branch 'master' into pie-menus
Conflicts:
	source/blender/windowmanager/WM_api.h
	source/blender/windowmanager/intern/wm_event_system.c
2014-06-05 19:59:07 +03:00
15c2ed08a6 Keep pie menus inside the screen area that spawned them.
More cleanup. *

* The reason there's so much cleanup is that the initial code was just
copied over from the popup menus. As I am getting more familiar with the
code I can see which parts are unnecessary or should be copied to new
functions etc.
2014-06-03 23:21:52 +03:00
69667a7e1f Solve pie menu selection not refreshing properly sometimes.
Reason here is that double press events could get chewed on handler
level. The issue Added an extra flag to hanldlers so that we can choose
to handle if we want.

Also cleanup debug messages
2014-06-03 19:27:15 +03:00
1709562a04 Some cleanup, refresh pie direction and drawing on the same events that
fired the pie menu, also some debug prints. Note, this is not ideal,
normally we want to just ignore those events, will look into that later.
2014-06-03 17:05:46 +03:00
8df7e10f30 minor refactoring and all pie operators return finished. 2014-06-03 00:40:36 +03:00
c6f727c667 Set the area rectangle to the whole screen area that spawned the pie
menu.

This means menus are now clipped correctly and their events are handled
in the whole area too, not only inside the bounding box of the buttons.
2014-06-02 23:57:59 +03:00
bc032b9880 Cancel the pie menu when releasing without a valid item selected. 2014-05-31 01:34:53 +03:00
cfb0ae2a17 For ease of testing, move object mode switch pie to be active across all
modes. Also modify custom python example pie and put it to Q key, sculpt mode.
2014-05-31 01:19:37 +03:00
929033a13b * Slight change on widget_box
* Pie menu operators return 'finished' to avoid evoking other operators
(maybe should be added to regular popup menus too?)
2014-05-31 00:51:41 +03:00
1f7a59ce7b UI changes:
* Central widget does not depend on width of menu text.
* Menu name hovers above the central widget.
2014-05-31 00:43:13 +03:00
8947cfe30c Add generic python operator that spawns a pie menu for a specific
operator enum.
2014-05-31 00:36:43 +03:00
e767a7bd44 Slightly offset the angles of diagonal pie menu items. Gives a more even
result. There may be a more accurate formula here but that works well
enough for now.
2014-05-30 20:07:04 +03:00
d13a194bb7 Press and release style interaction for pie menus
works by sending enter press and enter release events. May be somewhat
hacky but it should work.

+ minor cleanup.
2014-05-30 19:47:08 +03:00
95dca123d2 Merge branch 'master' into pie-menus 2014-05-30 16:17:02 +03:00
faf41c6c20 fix blenderplayer compilation 2014-05-27 17:53:30 +03:00
bbd0f6d37f Nice little widget indicator influenced from pie menu add-on 2014-05-27 00:31:04 +03:00
1f4337b770 Pies:
* More display code
* Add collision detection in one more place, now object mode pie
collision works correctly.
* Changed object mode pie shortcut to TAB
2014-05-27 00:03:41 +03:00
49e4866312 Refresh the pie area always on mousemove 2014-05-26 20:30:58 +03:00
e13bc48780 Angle range based collision detection on pie menu radial items. Also
some code to draw a central widget as well.
2014-05-26 19:53:02 +03:00
c3b6b8d86a Detect intersection of buttons with big segment from center of pie menu.
This already starts feeling like a pie menu. A better model for
intersection might be to store a direction for the pie menu widgets and
check if cursor is within the designated angle.

Also python menus don't work too well yet.
2014-05-26 01:32:33 +03:00
a1fbb85c76 Do not align pie menu item text on the left. Also some minor cleanup 2014-05-26 00:08:05 +03:00
f268dfe88e Merge branch 'master' into pie-menus 2014-05-25 19:47:01 +03:00
39dd7ec5b4 Pie menus beta code.
What is included here:

* Some initial code that lays out and displays items of a pie menu
 in a circular manner around the mouse. Collision detection is
 still not as expected for a pie menu.

* Code to spawn a pie menu for enums and operator enums (a bogus pie
menu for object mode is included, not yet set to any specific key).
For testing, the sculpt mode stroke mode enum is bound as a pie menu
to A key.

* Support to spawn pie menus from python.

Design could change radically, but best have the code here where all can
checkout and see the state of the code.
2014-04-22 14:24:28 +03:00
37 changed files with 1599 additions and 93 deletions

View File

@@ -525,6 +525,16 @@ processEvents(
continue;
}
#endif
/* when using autorepeat, some keypress events can actually come *after* the
* last keyrelease. The next code takes care of that */
if (xevent.type == KeyRelease) {
m_last_release_keycode = xevent.xkey.keycode;
m_last_release_time = xevent.xkey.time;
}
else if (xevent.type == KeyPress) {
if ((xevent.xkey.keycode == m_last_release_keycode) && ((xevent.xkey.time <= m_last_release_time)))
continue;
}
processEvent(&xevent);
anyProcessed = true;

View File

@@ -356,6 +356,10 @@ private:
* and stop accumulating all events generated before that */
Time m_last_warp;
/* detect autorepeat glitch */
unsigned int m_last_release_keycode;
Time m_last_release_time;
/**
* Return the ghost window associated with the
* X11 window xwind

View File

@@ -140,6 +140,15 @@ class WindowManager(bpy_types.ID):
finally:
self.pupmenu_end__internal(popup)
def popup_menu_pie(self, event, draw_func, title="", icon='NONE'):
import bpy
pie = self.piemenu_begin__internal(title, icon, event)
try:
draw_func(pie, bpy.context)
finally:
self.piemenu_end__internal(pie)
class _GenericBone:
"""

View File

@@ -527,7 +527,33 @@ class WM_OT_context_menu_enum(Operator):
context.window_manager.popup_menu(draw_func=draw_cb, title=prop.name, icon=prop.icon)
return {'PASS_THROUGH'}
return {'FINISHED'}
class WM_OT_context_pie_enum(Operator):
bl_idname = "wm.context_pie_enum"
bl_label = "Context Enum Pie"
bl_options = {'UNDO', 'INTERNAL'}
data_path = rna_path_prop
def invoke(self, context, event):
data_path = self.data_path
value = context_path_validate(context, data_path)
if value is Ellipsis:
return {'PASS_THROUGH'}
base_path, prop_string = data_path.rsplit(".", 1)
value_base = context_path_validate(context, base_path)
prop = value_base.bl_rna.properties[prop_string]
def draw_cb(self, context):
layout = self.layout
layout.prop(value_base, prop_string, expand=True)
context.window_manager.popup_menu_pie(draw_func=draw_cb, title=prop.name, icon=prop.icon, event=event)
return {'FINISHED'}
class WM_OT_context_set_id(Operator):

View File

@@ -216,6 +216,13 @@ class USERPREF_PT_interface(Panel):
sub.prop(view, "open_toplevel_delay", text="Top Level")
sub.prop(view, "open_sublevel_delay", text="Sub Level")
col.separator()
col.label(text="Pie Menus:")
sub = col.column(align=True)
sub.prop(view, "pie_animation_timeout")
sub.prop(view, "pie_initial_timeout")
sub.prop(view, "pie_menu_radius")
sub.prop(view, "pie_menu_threshold")
col.separator()
col.separator()
col.separator()
@@ -681,6 +688,9 @@ class USERPREF_PT_theme(Panel):
col.label(text="Menu:")
self._theme_widget_style(col, ui.wcol_menu)
col.label(text="Pie Menu:")
self._theme_widget_style(col, ui.wcol_pie_menu)
col.label(text="Pulldown:")
self._theme_widget_style(col, ui.wcol_pulldown)

View File

@@ -0,0 +1,32 @@
import bpy
from bpy.types import Menu
# spawn an edit mode selection pie (run while object is in edit mode to get a valid output)
class VIEW3D_PIE_template(Menu):
# label is displayed at the center of the pie menu.
bl_label = "Select Mode"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
# operator_enum will just spread all available options
# for the type enum of the operator on the pie
pie.operator_enum("mesh.select_mode", "type")
def register():
bpy.utils.register_class(VIEW3D_PIE_template)
def unregister():
bpy.utils.unregister_class(VIEW3D_PIE_template)
if __name__ == "__main__":
register()
bpy.ops.wm.call_menu_pie(name="VIEW3D_PIE_template")

View File

@@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 271
#define BLENDER_SUBVERSION 3
#define BLENDER_SUBVERSION 4
/* 262 was the last editmesh release but it has compatibility code for bmesh data */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5

View File

@@ -805,10 +805,14 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
// DIFFUSE
// color
if (ef->getDiffuse().isColor()) {
/* too high intensity can create artefacts (fireflies)
So here we take care that intensity is set to 0.8 wherever possible
*/
col = ef->getDiffuse().getColor();
ma->r = col.getRed();
ma->g = col.getGreen();
ma->b = col.getBlue();
ma->ref = max_ffff(col.getRed(), col.getGreen(), col.getBlue(), 0.8);
ma->r = col.getRed() / ma->ref;
ma->g = col.getGreen() / ma->ref;
ma->b = col.getBlue() / ma->ref;
}
// texture
else if (ef->getDiffuse().isTexture()) {

View File

@@ -35,6 +35,7 @@ struct ARegionType;
struct bContext;
void ED_spacetypes_init(void);
void ED_spacemacros_init(void);
/* the pluginnable API for export to editors */

View File

@@ -102,6 +102,7 @@ typedef struct uiLayout uiLayout;
#define UI_EMBOSSN 1 /* Nothing, only icon and/or text */
#define UI_EMBOSSP 2 /* Pulldown menu style */
#define UI_EMBOSST 3 /* Table */
#define UI_EMBOSSR 4 /* Pie Menu */
/* uiBlock->direction */
#define UI_DIRECTION (UI_TOP | UI_DOWN | UI_LEFT | UI_RIGHT)
@@ -137,6 +138,7 @@ typedef struct uiLayout uiLayout;
/* block->flag bits 14-17 are identical to but->drawflag bits */
#define UI_BLOCK_LIST_ITEM (1 << 19)
#define UI_BLOCK_RADIAL (1 << 20)
/* uiPopupBlockHandle->menuretval */
#define UI_RETURN_CANCEL (1 << 0) /* cancel all menus cascading */
@@ -359,6 +361,17 @@ struct uiLayout *uiPupMenuLayout(uiPopupMenu *head);
void uiPupMenuReports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL();
bool uiPupMenuInvoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2);
/* Pie menus */
typedef struct uiPieMenu uiPieMenu;
void uiPieMenuInvoke(struct bContext *C, const char *idname, const struct wmEvent *event);
void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
const char *propname, const struct wmEvent *event);
void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path, const struct wmEvent *event);
struct uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const struct wmEvent *event) ATTR_NONNULL();
void uiPieMenuEnd(struct bContext *C, uiPieMenu *pie);
struct uiLayout *uiPieMenuLayout(struct uiPieMenu *pie);
/* Popup Blocks
*
* Functions used to create popup blocks. These are like popup menus
@@ -416,7 +429,8 @@ typedef enum {
UI_BLOCK_BOUNDS_TEXT,
UI_BLOCK_BOUNDS_POPUP_MOUSE,
UI_BLOCK_BOUNDS_POPUP_MENU,
UI_BLOCK_BOUNDS_POPUP_CENTER
UI_BLOCK_BOUNDS_POPUP_CENTER,
UI_BLOCK_BOUNDS_PIE_CENTER,
} eBlockBoundsCalc;
void uiBoundsBlock(struct uiBlock *block, int addval);
@@ -704,7 +718,7 @@ void UI_panel_category_draw_all(struct ARegion *ar, const
* as screen/ if ED_KEYMAP_UI is set, or internally in popup functions. */
void UI_add_region_handlers(struct ListBase *handlers);
void UI_add_popup_handlers(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup);
void UI_add_popup_handlers(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click);
void UI_remove_popup_handlers(struct ListBase *handlers, uiPopupBlockHandle *popup);
void UI_remove_popup_handlers_all(struct bContext *C, struct ListBase *handlers);
@@ -736,6 +750,7 @@ void UI_exit(void);
#define UI_LAYOUT_HEADER 1
#define UI_LAYOUT_MENU 2
#define UI_LAYOUT_TOOLBAR 3
#define UI_LAYOUT_PIEMENU 4
#define UI_UNIT_X ((void)0, U.widget_unit)
#define UI_UNIT_Y ((void)0, U.widget_unit)
@@ -826,8 +841,8 @@ uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, struct Point
uiLayout *uiLayoutAbsolute(uiLayout *layout, int align);
uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align);
uiLayout *uiLayoutOverlap(uiLayout *layout);
uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout);
uiLayout *uiLayoutRadial(uiLayout *layout);
/* templates */
void uiTemplateHeader(uiLayout *layout, struct bContext *C);

View File

@@ -321,6 +321,20 @@ static void ui_centered_bounds_block(wmWindow *window, uiBlock *block)
ui_bounds_block(block);
}
static void ui_centered_pie_bounds_block(uiBlock *block)
{
const int xy[2] = {
block->pie_data.pie_center_spawned[0],
block->pie_data.pie_center_spawned[1]
};
ui_block_translate(block, xy[0], xy[1]);
/* now recompute bounds and safety */
ui_bounds_block(block);
}
static void ui_popup_bounds_block(wmWindow *window, uiBlock *block,
eBlockBoundsCalc bounds_calc, const int xy[2])
{
@@ -1062,6 +1076,42 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
return found;
}
/* this goes in a seemingly weird pattern:
*
* 4
* 5 6
* 1 2
* 7 8
* 3
*
* but it's actually quite logical. It's designed to be 'upwards compatible'
* for muscle memory so that the menu item locations are fixed and don't move
* as new items are added to the menu later on. It also optimises efficiency -
* a radial menu is best kept symmetrical, with as large an angle between
* items as possible, so that the gestural mouse movements can be fast and inexact.
* It starts off with two opposite sides for the first two items
* then joined by the one below for the third (this way, even with three items,
* the menu seems to still be 'in order' reading left to right). Then the fourth is
* added to complete the compass directions. From here, it's just a matter of
* subdividing the rest of the angles for the last 4 items.
*
* --Matt 07/2006
*/
const char ui_radial_dir_order[8] = {
UI_RADIAL_W, UI_RADIAL_E, UI_RADIAL_S, UI_RADIAL_N,
UI_RADIAL_NW, UI_RADIAL_NE, UI_RADIAL_SW, UI_RADIAL_SE};
const char ui_radial_dir_to_numpad[8] = {8, 9, 6, 3, 2, 1, 4, 7};
const short ui_radial_dir_to_angle_visual[8] = {90, 40, 0, 320, 270, 220, 180, 140};
const short ui_radial_dir_to_angle[8] = {90, 45, 0, 315, 270, 225, 180, 135};
static void ui_but_pie_direction_string(uiBut *but, char *buf, int size)
{
BLI_assert(but->pie_dir < ARRAY_SIZE(ui_radial_dir_to_numpad));
BLI_snprintf(buf, size, "%d", ui_radial_dir_to_numpad[but->pie_dir]);
}
static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
{
uiBut *but;
@@ -1071,13 +1121,23 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
if (block->rect.xmin != block->rect.xmax)
return;
for (but = block->buttons.first; but; but = but->next) {
if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
ui_but_add_shortcut(but, buf, false);
if (block->flag & UI_BLOCK_RADIAL) {
for (but = block->buttons.first; but; but = but->next) {
if (but->pie_dir != UI_RADIAL_NONE) {
ui_but_pie_direction_string(but, buf, sizeof(buf));
ui_but_add_shortcut(but, buf, false);
}
}
else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) {
ui_but_add_shortcut(but, buf, false);
}
else {
for (but = block->buttons.first; but; but = but->next) {
if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
ui_but_add_shortcut(but, buf, false);
}
else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) {
ui_but_add_shortcut(but, buf, false);
}
}
}
}
@@ -1173,6 +1233,9 @@ void uiEndBlock_ex(const bContext *C, uiBlock *block, const int xy[2])
case UI_BLOCK_BOUNDS_POPUP_CENTER:
ui_centered_bounds_block(window, block);
break;
case UI_BLOCK_BOUNDS_PIE_CENTER:
ui_centered_pie_bounds_block(block);
break;
/* fallback */
case UI_BLOCK_BOUNDS_POPUP_MOUSE:
@@ -1244,6 +1307,10 @@ void uiDrawBlock(const bContext *C, uiBlock *block)
rcti rect;
int multisample_enabled;
/* early exit if cancelled */
if ((block->flag & UI_BLOCK_RADIAL) && (block->pie_data.flags & UI_PIE_FINISHED))
return;
/* get menu region or area region */
ar = CTX_wm_menu(C);
if (!ar)
@@ -1279,7 +1346,9 @@ void uiDrawBlock(const bContext *C, uiBlock *block)
wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f);
/* back */
if (block->flag & UI_BLOCK_LOOP)
if (block->flag & UI_BLOCK_RADIAL)
ui_draw_pie_center(block);
else if (block->flag & UI_BLOCK_LOOP)
ui_draw_menu_back(&style, block, &rect);
else if (block->panel)
ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar));
@@ -3002,6 +3071,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
but->lock = block->lock;
but->lockstr = block->lockstr;
but->dt = block->dt;
but->pie_dir = UI_RADIAL_NONE;
but->block = block; /* pointer back, used for frontbuffer status, and picker */
@@ -3028,8 +3098,11 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
}
}
if ((block->flag & UI_BLOCK_LOOP) ||
ELEM(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
if (block->flag & UI_BLOCK_RADIAL) {
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
else if ((block->flag & UI_BLOCK_LOOP) ||
ELEM(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
{
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}

View File

@@ -116,6 +116,7 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve
#define BUTTON_TOOLTIP_DELAY 0.500
#define BUTTON_FLASH_DELAY 0.020
#define MENU_SCROLL_INTERVAL 0.1
#define PIE_MENU_INTERVAL 0.01
#define BUTTON_AUTO_OPEN_THRESH 0.3
#define BUTTON_MOUSE_TOWARDS_THRESH 1.0
/* pixels to move the cursor to get out of keyboard navigation */
@@ -1238,7 +1239,7 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
WM_event_add_ui_handler(C, &data->window->modalhandlers,
ui_handler_region_drag_toggle,
ui_handler_region_drag_toggle_remove,
drag_info);
drag_info, false);
CTX_wm_region_set(C, ar_prev);
}
@@ -6377,6 +6378,43 @@ static bool ui_but_contains_pt(uiBut *but, float mx, float my)
return BLI_rctf_isect_pt(&but->rect, mx, my);
}
static void ui_but_pie_dir__internal(RadialDirection dir, float vec[2], const short angles[8])
{
float angle;
BLI_assert(dir != UI_RADIAL_NONE);
angle = DEG2RADF((float)angles[dir]);
vec[0] = cosf(angle);
vec[1] = sinf(angle);
}
void ui_but_pie_dir_visual(RadialDirection dir, float vec[2])
{
ui_but_pie_dir__internal(dir, vec, ui_radial_dir_to_angle_visual);
}
void ui_but_pie_dir(RadialDirection dir, float vec[2])
{
ui_but_pie_dir__internal(dir, vec, ui_radial_dir_to_angle);
}
static bool ui_but_isect_pie_seg(uiBlock *block, uiBut *but)
{
const float angle_range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_4 : M_PI_4 / 2.0;
float vec[2];
if (block->pie_data.flags & UI_PIE_INVALID_DIR)
return false;
ui_but_pie_dir(but->pie_dir, vec);
if (saacos(dot_v2v2(vec, block->pie_data.pie_dir)) < angle_range)
return true;
return false;
}
uiBut *ui_but_find_activated(ARegion *ar)
{
uiBlock *block;
@@ -6495,6 +6533,7 @@ static bool ui_mouse_inside_region(ARegion *ar, int x, int y)
static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
{
uiBlock *block = but->block;
float mx, my;
if (!ui_mouse_inside_region(ar, x, y))
return false;
@@ -6502,10 +6541,16 @@ static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
mx = x;
my = y;
ui_window_to_block_fl(ar, but->block, &mx, &my);
ui_window_to_block_fl(ar, block, &mx, &my);
if (!ui_but_contains_pt(but, mx, my))
if (but->dt == UI_EMBOSSR) {
if (!ui_but_isect_pie_seg(block, but)) {
return false;
}
}
else if (!ui_but_contains_pt(but, mx, my)) {
return false;
}
return true;
}
@@ -6559,7 +6604,13 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c
for (but = block->buttons.last; but; but = but->prev) {
if (ui_is_but_interactive(but, labeledit)) {
if (ui_but_contains_pt(but, mx, my)) {
if (but->pie_dir != UI_RADIAL_NONE) {
if (ui_but_isect_pie_seg(block, but)) {
butover = but;
break;
}
}
else if (ui_but_contains_pt(but, mx, my)) {
butover = but;
break;
}
@@ -6764,7 +6815,7 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (!(but->block->handle && but->block->handle->popup)) {
if (button_modal_state(state)) {
if (!button_modal_state(data->state))
WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data);
WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, false);
}
else {
if (button_modal_state(data->state)) {
@@ -7914,6 +7965,30 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
return retval;
}
void ui_block_calculate_pie_segment(uiBlock *block, const float event_xy[2])
{
float seg1[2];
float seg2[2];
float len;
if (block->pie_data.flags & UI_PIE_INITIAL_DIRECTION) {
copy_v2_v2(seg1, block->pie_data.pie_center_init);
}
else {
copy_v2_v2(seg1, block->pie_data.pie_center_spawned);
}
sub_v2_v2v2(seg2, event_xy, seg1);
len = normalize_v2_v2(block->pie_data.pie_dir, seg2);
/* ten pixels for now, a bit arbitrary */
if (len < U.pie_menu_threshold * U.pixelsize)
block->pie_data.flags |= UI_PIE_INVALID_DIR;
else
block->pie_data.flags &= ~UI_PIE_INVALID_DIR;
}
static int ui_handle_menu_event(
bContext *C, const wmEvent *event, uiPopupBlockHandle *menu,
int level, const bool is_parent_inside, const bool is_parent_menu, const bool is_floating)
@@ -8415,10 +8490,311 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
ui_mouse_motion_towards_reinit(menu, &event->x);
}
if (menu->menuretval)
if (menu->menuretval) {
/* pie menus should not close but wait for release instead */
if ((block->flag & UI_BLOCK_RADIAL) &&
!(block->pie_data.flags & UI_PIE_CLICK_STYLE))
{
menu->menuretval = 0;
block->pie_data.flags |= UI_PIE_FINISHED;
}
return WM_UI_HANDLER_CONTINUE;
else
}
else {
return WM_UI_HANDLER_BREAK;
}
}
static bool ui_but_pie_menu_supported_apply(uiBut *but)
{
return (but->type != NUMSLI);
}
static int ui_but_pie_menu_apply(bContext *C, uiPopupBlockHandle *menu, uiBut *but, bool force_close, bool click_style)
{
int retval = WM_UI_HANDLER_BREAK;
if (but && ui_but_pie_menu_supported_apply(but)) {
if (but->type == MENU) {
/* forcing the pie menu to close will not handle menus */
if (!force_close) {
uiBut *active_but = ui_but_find_activated(menu->region);
if (active_but) {
button_activate_exit(C, active_but, active_but->active, false, false);
}
button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OPEN);
return retval;
}
else {
menu->menuretval = UI_RETURN_CANCEL;
}
}
else {
ui_apply_button(C, but->block, but, but->active, false);
button_activate_exit((bContext *)C, but, but->active, false, true);
if (!(click_style || force_close)) {
but->block->pie_data.flags |= UI_PIE_FINISHED;
menu->menuretval = 0;
}
else {
menu->menuretval = UI_RETURN_OK;
}
}
}
else {
uiBlock *block = menu->region->uiblocks.first;
if (!(click_style || force_close)) {
block->pie_data.flags |= UI_PIE_FINISHED;
}
else {
menu->menuretval = UI_RETURN_CANCEL;
}
ED_region_tag_redraw(menu->region);
}
return retval;
}
static uiBut *ui_block_pie_dir_activate(uiBlock *block, const wmEvent *event, RadialDirection dir)
{
uiBut *but;
if ((block->flag & UI_BLOCK_NUMSELECT) && event->val == KM_PRESS) {
for (but = block->buttons.first; but; but = but->next) {
if (but->pie_dir == dir && !ELEM(but->type, SEPR, SEPRLINE)) {
return but;
}
}
}
return NULL;
}
static int ui_but_pie_button_activate(bContext *C, uiBut *but, uiPopupBlockHandle *menu, bool is_click_style)
{
uiBut *active_but;
if (but == NULL)
return WM_UI_HANDLER_BREAK;
active_but = ui_but_find_activated(menu->region);
if (active_but)
button_activate_exit(C, active_but, active_but->active, false, false);
button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OVER);
return ui_but_pie_menu_apply(C, menu, but, false, is_click_style);
}
static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle *menu)
{
ARegion *ar;
uiBlock *block;
uiBut *but;
float event_xy[2];
double duration;
bool is_click_style;
/* we block all events, this is modal interaction, except for drop events which is described below */
int retval = WM_UI_HANDLER_BREAK;
if (event->type == EVT_DROP) {
/* may want to leave this here for later if we support pie ovens */
retval = WM_UI_HANDLER_CONTINUE;
}
ar = menu->region;
block = ar->uiblocks.first;
is_click_style = (block->pie_data.flags & UI_PIE_CLICK_STYLE);
if (menu->scrolltimer == NULL) {
menu->scrolltimer =
WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, PIE_MENU_INTERVAL);
menu->scrolltimer->duration = 0.0;
}
duration = menu->scrolltimer->duration;
if (event->type == TIMER) {
if (event->customdata == menu->scrolltimer) {
/* deactivate initial direction after a while */
if (duration > 0.01 * U.pie_initial_timeout) {
block->pie_data.flags &= ~UI_PIE_INITIAL_DIRECTION;
}
/* handle animation */
if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) {
uiBut *but;
double final_time = 0.01 * U.pie_animation_timeout;
float fac = duration / final_time;
float pie_radius = U.pie_menu_radius * UI_DPI_FAC;
if (fac > 1.0f) {
fac = 1.0f;
block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED;
}
pie_radius *= fac;
for (but = block->buttons.first; but; but = but->next) {
if (but->pie_dir != UI_RADIAL_NONE) {
float dir[2];
ui_but_pie_dir_visual(but->pie_dir, dir);
mul_v2_fl(dir, pie_radius );
add_v2_v2(dir, block->pie_data.pie_center_spawned);
BLI_rctf_recenter(&but->rect, dir[0], dir[1]);
}
}
block->pie_data.alphafac = fac;
ED_region_tag_redraw(ar);
}
}
}
event_xy[0] = event->x;
event_xy[1] = event->y;
ui_window_to_block_fl(ar, block, &event_xy[0], &event_xy[1]);
ui_block_calculate_pie_segment(block, event_xy);
if (block->pie_data.flags & UI_PIE_FINISHED) {
if ((event->type == block->pie_data.event && event->val == KM_RELEASE) ||
((event->type == RIGHTMOUSE || event->type == ESCKEY) && (event->val == KM_PRESS)))
{
menu->menuretval = UI_RETURN_OK;
}
ED_region_tag_redraw(ar);
return WM_UI_HANDLER_BREAK;
}
if (event->type == block->pie_data.event) {
if (event->val != KM_RELEASE) {
ui_handle_menu_button(C, event, menu);
/* why redraw here? It's simple, we are getting many double click events here.
* Those operate like mouse move events almost */
ED_region_tag_redraw(ar);
}
else {
/* distance from initial point */
if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) < PIE_CLICK_THRESHOLD_SQ) {
block->pie_data.flags |= UI_PIE_CLICK_STYLE;
}
else if (!is_click_style) {
uiBut *but = ui_but_find_activated(menu->region);
retval = ui_but_pie_menu_apply(C, menu, but, true, is_click_style);
}
}
}
else {
/* direction from numpad */
RadialDirection num_dir = UI_RADIAL_NONE;
switch (event->type) {
case MOUSEMOVE:
/* mouse move should always refresh the area for pie menus */
ui_handle_menu_button(C, event, menu);
ED_region_tag_redraw(ar);
break;
case LEFTMOUSE:
if (event->val == KM_PRESS) {
uiBut *but = ui_but_find_activated(menu->region);
retval = ui_but_pie_menu_apply(C, menu, but, false, is_click_style);
}
break;
case ESCKEY:
case RIGHTMOUSE:
if (!is_click_style) {
block->pie_data.flags |= UI_PIE_FINISHED;
menu->menuretval = 0;
ED_region_tag_redraw(ar);
}
else
menu->menuretval = UI_RETURN_CANCEL;
break;
case AKEY:
case BKEY:
case CKEY:
case DKEY:
case EKEY:
case FKEY:
case GKEY:
case HKEY:
case IKEY:
case JKEY:
case KKEY:
case LKEY:
case MKEY:
case NKEY:
case OKEY:
case PKEY:
case QKEY:
case RKEY:
case SKEY:
case TKEY:
case UKEY:
case VKEY:
case WKEY:
case XKEY:
case YKEY:
case ZKEY:
{
if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
(event->shift == 0) &&
(event->ctrl == 0) &&
(event->oskey == 0))
{
for (but = block->buttons.first; but; but = but->next) {
if (but->menu_key == event->type) {
ui_but_pie_button_activate(C, but, menu, is_click_style);
}
}
}
break;
}
#define CASE_NUM_TO_DIR(n, d) \
case (ZEROKEY + n): case (PAD0 + n): \
{ if (num_dir == UI_RADIAL_NONE) num_dir = d; } (void)0
CASE_NUM_TO_DIR(1, UI_RADIAL_SW);
CASE_NUM_TO_DIR(2, UI_RADIAL_S);
CASE_NUM_TO_DIR(3, UI_RADIAL_SE);
CASE_NUM_TO_DIR(4, UI_RADIAL_W);
CASE_NUM_TO_DIR(6, UI_RADIAL_E);
CASE_NUM_TO_DIR(7, UI_RADIAL_NW);
CASE_NUM_TO_DIR(8, UI_RADIAL_N);
CASE_NUM_TO_DIR(9, UI_RADIAL_NE);
{
but = ui_block_pie_dir_activate(block, event, num_dir);
retval = ui_but_pie_button_activate(C, but, menu, is_click_style);
break;
}
#undef CASE_NUM_TO_DIR
default:
retval = ui_handle_menu_button(C, event, menu);
break;
}
}
return retval;
}
static int ui_handle_menus_recursive(
@@ -8440,17 +8816,21 @@ static int ui_handle_menus_recursive(
uiBlock *block = menu->region->uiblocks.first;
const bool is_menu = ui_block_is_menu(block);
bool inside = false;
/* root pie menus accept the key that spawned them as double click to improve responsiveness */
bool do_recursion = (!(block->flag & UI_BLOCK_RADIAL) || event->type != block->pie_data.event);
if (is_parent_inside == false) {
int mx, my;
if (do_recursion) {
if (is_parent_inside == false) {
int mx, my;
mx = event->x;
my = event->y;
ui_window_to_block(menu->region, block, &mx, &my);
inside = BLI_rctf_isect_pt(&block->rect, mx, my);
mx = event->x;
my = event->y;
ui_window_to_block(menu->region, block, &mx, &my);
inside = BLI_rctf_isect_pt(&block->rect, mx, my);
}
retval = ui_handle_menus_recursive(C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false);
}
retval = ui_handle_menus_recursive(C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false);
}
/* now handle events for our own menu */
@@ -8483,7 +8863,12 @@ static int ui_handle_menus_recursive(
}
}
else {
retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
uiBlock *block = menu->region->uiblocks.first;
if (block->flag & UI_BLOCK_RADIAL)
retval = ui_handler_pie(C, event, menu);
else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK)
retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
}
}
@@ -8698,12 +9083,12 @@ static void ui_handler_remove_popup(bContext *C, void *userdata)
void UI_add_region_handlers(ListBase *handlers)
{
WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL, false);
WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL);
WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL, false);
}
void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup)
void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click)
{
WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup);
WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup, accept_dbl_click);
}
void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup)

View File

@@ -88,6 +88,7 @@ typedef enum {
UI_WTYPE_PULLDOWN,
UI_WTYPE_MENU_ITEM,
UI_WTYPE_MENU_ITEM_RADIAL,
UI_WTYPE_MENU_BACK,
/* specials */
@@ -121,6 +122,24 @@ enum {
/* warn: rest of uiBut->flag in UI_interface.h */
};
/* but->pie_dir */
typedef enum RadialDirection {
UI_RADIAL_NONE = -1,
UI_RADIAL_N = 0,
UI_RADIAL_NE = 1,
UI_RADIAL_E = 2,
UI_RADIAL_SE = 3,
UI_RADIAL_S = 4,
UI_RADIAL_SW = 5,
UI_RADIAL_W = 6,
UI_RADIAL_NW = 7,
} RadialDirection;
extern const char ui_radial_dir_order[8];
extern const char ui_radial_dir_to_numpad[8];
extern const short ui_radial_dir_to_angle_visual[8];
extern const short ui_radial_dir_to_angle[8];
/* internal panel drawing defines */
#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */
#define PNL_HEADER (UI_UNIT_Y + 4) /* 24 default */
@@ -144,6 +163,19 @@ enum {
/* split numbuts by ':' and align l/r */
#define USE_NUMBUTS_LR_ALIGN
/* PieMenuData->flags */
enum {
UI_PIE_DEGREES_RANGE_LARGE = (1 << 0), /* pie menu item collision is detected at 90 degrees */
UI_PIE_INITIAL_DIRECTION = (1 << 1), /* use initial center of pie menu to calculate direction */
UI_PIE_3_ITEMS = (1 << 2), /* pie menu has only 3 items, careful when centering */
UI_PIE_INVALID_DIR = (1 << 3), /* mouse not far enough from center position */
UI_PIE_FINISHED = (1 << 4), /* pie menu finished but we still wait for a release event */
UI_PIE_CLICK_STYLE = (1 << 5), /* pie menu changed to click style, click to confirm */
UI_PIE_ANIMATION_FINISHED = (1 << 6), /* pie animation finished, do not calculate any more motio */
};
#define PIE_CLICK_THRESHOLD_SQ 50.0f
typedef struct uiLinkLine { /* only for draw/edit */
struct uiLinkLine *next, *prev;
struct uiBut *from, *to;
@@ -227,6 +259,7 @@ struct uiBut {
BIFIconID icon;
bool lock;
char dt; /* drawtype: UI_EMBOSS, UI_EMBOSSN ... etc, copied from the block */
signed char pie_dir; /* direction in a pie menu, used for collision detection (RadialDirection) */
char changed; /* could be made into a single flag */
unsigned char unit_type; /* so buttons can support unit systems which are not RNA */
short modifier_key;
@@ -274,6 +307,15 @@ struct uiBut {
uiBlock *block;
};
struct PieMenuData {
float pie_dir[2];
float pie_center_init[2];
float pie_center_spawned[2];
int flags;
int event; /* initial event used to fire the pie menu, store here so we can query for release */
float alphafac;
};
struct uiBlock {
uiBlock *next, *prev;
@@ -356,6 +398,7 @@ struct uiBlock {
char display_device[64]; /* display device name used to display this block,
* used by color widgets to transform colors from/to scene linear
*/
struct PieMenuData pie_data;
};
typedef struct uiSafetyRct {
@@ -561,6 +604,9 @@ extern int ui_button_open_menu_direction(uiBut *but);
extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
extern uiBut *ui_but_find_activated(struct ARegion *ar);
bool ui_but_is_editable(const uiBut *but);
void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]);
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
void ui_block_calculate_pie_segment(struct uiBlock *block, const float event_xy[2]);
void ui_button_clipboard_free(void);
void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
@@ -571,6 +617,7 @@ uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
void ui_draw_pie_center(uiBlock *block);
uiWidgetColors *ui_tooltip_get_theme(void);
void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *block, rcti *rect);
void ui_draw_search_back(struct uiStyle *style, uiBlock *block, rcti *rect);

View File

@@ -106,6 +106,7 @@ typedef enum uiItemType {
ITEM_LAYOUT_ABSOLUTE,
ITEM_LAYOUT_SPLIT,
ITEM_LAYOUT_OVERLAP,
ITEM_LAYOUT_RADIAL,
ITEM_LAYOUT_ROOT
#if 0
@@ -218,7 +219,9 @@ static int ui_item_fit(int item, int pos, int all, int available, int last, int
static int ui_layout_vary_direction(uiLayout *layout)
{
return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND) ? UI_ITEM_VARY_X : UI_ITEM_VARY_Y;
return ((ELEM(layout->root->type, UI_LAYOUT_HEADER, UI_LAYOUT_PIEMENU) ||
(layout->alignment != UI_LAYOUT_ALIGN_EXPAND)) ?
UI_ITEM_VARY_X : UI_ITEM_VARY_Y);
}
/* estimated size of text + icon */
@@ -553,15 +556,24 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt
*/
uiBut *but;
uiLayout *layout_radial = NULL;
EnumPropertyItem *item, *item_array;
const char *name;
int itemw, icon, value;
bool free;
bool radial = (layout->root->type == UI_LAYOUT_PIEMENU);
RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
if (radial)
RNA_property_enum_items_gettexted_all(block->evil_C, ptr, prop, &item_array, NULL, &free);
else
RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
/* we dont want nested rows, cols in menus */
if (layout->root->type != UI_LAYOUT_MENU) {
if (radial) {
layout_radial = uiLayoutRadial(layout);
uiBlockSetCurLayout(block, layout_radial);
}
else if (layout->root->type != UI_LAYOUT_MENU) {
uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
}
else {
@@ -569,8 +581,11 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt
}
for (item = item_array; item->identifier; item++) {
if (!item->identifier[0])
if (!item->identifier[0]) {
if (radial)
uiItemS(layout_radial);
continue;
}
name = (!uiname || uiname[0]) ? item->name : "";
icon = item->icon;
@@ -869,6 +884,8 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
PointerRNA ptr;
PropertyRNA *prop;
uiBlock *block = layout->root->block;
const bool radial = (layout->item.type == ITEM_LAYOUT_RADIAL) ||
((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
if (!ot || !ot->srna) {
ui_item_disabled(layout, opname);
@@ -887,10 +904,24 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
if (prop && RNA_property_type(prop) == PROP_ENUM) {
EnumPropertyItem *item, *item_array = NULL;
bool free;
uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
uiLayout *column = uiLayoutColumn(split, layout->align);
uiLayout *split;
uiLayout *target;
if (radial) {
target = uiLayoutRadial(layout);
}
else {
split = uiLayoutSplit(layout, 0.0f, false);
target = uiLayoutColumn(split, layout->align);
}
if (radial) {
RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, NULL, &free);
}
else {
RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free);
}
RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free);
for (item = item_array; item->identifier; item++) {
if (item->identifier[0]) {
PointerRNA tptr;
@@ -905,20 +936,24 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
}
RNA_property_enum_set(&tptr, prop, item->value);
uiItemFullO_ptr(column, ot, item->name, item->icon, tptr.data, context, flag);
uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag);
ui_but_tip_from_enum_item(block->buttons.last, item);
}
else {
if (item->name) {
uiBut *but;
if (item != item_array) {
column = uiLayoutColumn(split, layout->align);
if (item != item_array && !radial) {
target = uiLayoutColumn(split, layout->align);
/* inconsistent, but menus with labels do not look good flipped */
block->flag |= UI_BLOCK_NO_FLIP;
}
if (item->icon) {
uiItemL(column, item->name, item->icon);
if (item->icon || radial) {
uiItemL(target, item->name, item->icon);
but = block->buttons.last;
}
else {
@@ -928,8 +963,14 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
}
ui_but_tip_from_enum_item(but, item);
}
else { /* XXX bug here, colums draw bottom item badly */
uiItemS(column);
else {
if (radial) {
uiItemS(target);
}
else {
/* XXX bug here, colums draw bottom item badly */
uiItemS(target);
}
}
}
}
@@ -2072,16 +2113,135 @@ static void ui_litem_layout_column(uiLayout *litem)
litem->y = y;
}
/* calculates the angle of a specified button in a radial menu,
* stores a float vector in unit circle */
static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
{
RadialDirection dir;
BLI_assert(itemnum < 8);
dir = ui_radial_dir_order[itemnum];
ui_but_pie_dir_visual(dir, vec);
return dir;
}
static bool ui_item_is_radial_displayable(uiItem *item)
{
if ((item->type == ITEM_BUTTON) && (((uiButtonItem *)item)->but->type == LABEL))
return false;
return true;
}
static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
{
if (ELEM(bitem->but->type, SEPR, SEPRLINE))
return false;
return true;
}
static void ui_litem_layout_radial(uiLayout *litem)
{
uiItem *item;
int itemh, itemw, x, y;
int itemnum = 0;
int totitems = 0;
int minx, miny, maxx, maxy;
/* For the radial layout we will use Matt Ebb's design
* for radiation, see http://mattebb.com/weblog/radiation/
* also the old code at http://developer.blender.org/T5103
*/
int pie_radius = U.pie_menu_radius * UI_DPI_FAC;
x = litem->x;
y = litem->y;
minx = x, miny = y, maxx = x, maxy = y;
/* first count total items */
for (item = litem->items.first; item; item = item->next)
totitems++;
if (totitems < 5)
litem->root->block->pie_data.flags |= UI_PIE_DEGREES_RANGE_LARGE;
if (totitems == 3)
litem->root->block->pie_data.flags |= UI_PIE_3_ITEMS;
for (item = litem->items.first; item; item = item->next) {
/* not all button types are drawn in a radial menu, do filtering here */
if (ui_item_is_radial_displayable(item)) {
RadialDirection dir;
float vec[2];
dir = ui_get_radialbut_vec(vec, itemnum);
itemnum++;
if (item->type == ITEM_BUTTON) {
uiButtonItem *bitem = (uiButtonItem *) item;
bitem->but->pie_dir = dir;
/* scale the buttons */
bitem->but->rect.ymax *= 1.5f;
/* add a little bit more here to include number */
bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
/* enable drawing as pie item if supported by widget */
if (ui_item_is_radial_drawable(bitem))
bitem->but->dt = UI_EMBOSSR;
}
ui_item_size(item, &itemw, &itemh);
ui_item_position(item, x + vec[0] * pie_radius - itemw / 2, y + vec[1] * pie_radius - itemh / 2, itemw, itemh);
minx = min_ii(minx, x + vec[0] * pie_radius - itemw / 2);
maxx = max_ii(maxx, x + vec[0] * pie_radius + itemw / 2);
miny = min_ii(miny, y + vec[1] * pie_radius - itemh / 2);
maxy = max_ii(maxy, y + vec[1] * pie_radius + itemh / 2);
}
}
litem->x = minx;
litem->y = miny;
litem->w = maxx - minx;
litem->h = maxy - miny;
}
/* root layout */
static void ui_litem_estimate_root(uiLayout *UNUSED(litem))
{
/* nothing to do */
}
static void ui_litem_layout_root_radial(uiLayout *litem)
{
/* first item is pie menu title, align on center of menu */
uiItem *item = litem->items.first;
if (item->type == ITEM_BUTTON) {
int itemh, itemw, x, y;
x = litem->x;
y = litem->y;
ui_item_size(item, &itemw, &itemh);
ui_item_position(item, x - itemw / 2, y + 2 * UI_UNIT_Y, itemw, itemh);
}
}
static void ui_litem_layout_root(uiLayout *litem)
{
if (litem->root->type == UI_LAYOUT_HEADER)
ui_litem_layout_row(litem);
else if (litem->root->type == UI_LAYOUT_PIEMENU)
ui_litem_layout_root_radial(litem);
else
ui_litem_layout_column(litem);
}
@@ -2497,6 +2657,40 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
return box;
}
uiLayout *uiLayoutRadial(uiLayout *layout)
{
uiLayout *litem;
uiItem *item;
/* radial layouts are only valid for radial menus */
if (layout->root->type != UI_LAYOUT_PIEMENU)
return ui_item_local_sublayout(layout, layout, 0);
/* only one radial wheel per root layout is allowed, so check and return that, if it exists */
for (item = layout->root->layout->items.first; item; item = item->next) {
litem = (uiLayout *)item;
if (litem->item.type == ITEM_LAYOUT_RADIAL) {
uiBlockSetCurLayout(layout->root->block, litem);
return litem;
}
}
litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial");
litem->item.type = ITEM_LAYOUT_RADIAL;
litem->root = layout->root;
litem->active = true;
litem->enabled = true;
litem->context = layout->context;
litem->redalert = layout->redalert;
litem->w = layout->w;
BLI_addtail(&layout->root->layout->items, litem);
uiBlockSetCurLayout(layout->root->block, litem);
return litem;
}
uiLayout *uiLayoutBox(uiLayout *layout)
{
return (uiLayout *)ui_layout_box(layout, ROUNDBOX);
@@ -2843,6 +3037,9 @@ static void ui_item_layout(uiItem *item)
case ITEM_LAYOUT_OVERLAP:
ui_litem_layout_overlap(litem);
break;
case ITEM_LAYOUT_RADIAL:
ui_litem_layout_radial(litem);
break;
default:
break;
}
@@ -2916,7 +3113,7 @@ uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int siz
layout->enabled = 1;
layout->context = NULL;
if (type == UI_LAYOUT_MENU)
if (type == UI_LAYOUT_MENU || type == UI_LAYOUT_PIEMENU)
layout->space = 0;
if (dir == UI_LAYOUT_HORIZONTAL) {

View File

@@ -1912,7 +1912,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
pa->activedata = data;
WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa);
WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
}
if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG))

View File

@@ -43,6 +43,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "PIL_time.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_report.h"
@@ -1704,18 +1706,69 @@ uiBlock *ui_popup_block_refresh(
BLI_addhead(&block->saferct, saferct);
}
/* clip block with window boundary */
ui_popup_block_clip(window, block);
/* the block and buttons were positioned in window space as in 2.4x, now
* these menu blocks are regions so we bring it back to region space.
* additionally we add some padding for the menu shadow or rounded menus */
ar->winrct.xmin = block->rect.xmin - width;
ar->winrct.xmax = block->rect.xmax + width;
ar->winrct.ymin = block->rect.ymin - width;
ar->winrct.ymax = block->rect.ymax + MENU_TOP;
ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
if (block->flag & UI_BLOCK_RADIAL) {
uiBut *but;
int win_width = UI_SCREEN_MARGIN;
int winx, winy;
int x_offset = 0, y_offset = 0;
winx = WM_window_pixels_x(window);
winy = WM_window_pixels_y(window);
copy_v2_v2(block->pie_data.pie_center_init, block->pie_data.pie_center_spawned);
/* only try translation if area is large enough */
if (BLI_rctf_size_x(&block->rect) < winx - (2.0f * win_width)) {
if (block->rect.xmin < win_width ) x_offset += win_width - block->rect.xmin;
if (block->rect.xmax > winx - win_width) x_offset += winx - win_width - block->rect.xmax;
}
if (BLI_rctf_size_y(&block->rect) < winy - (2.0f * win_width)) {
if (block->rect.ymin < win_width ) y_offset += win_width - block->rect.ymin;
if (block->rect.ymax > winy - win_width) y_offset += winy - win_width - block->rect.ymax;
}
/* if we are offsetting set up initial data for timeout functionality */
if ((x_offset != 0) || (y_offset != 0)) {
block->pie_data.pie_center_spawned[0] += x_offset;
block->pie_data.pie_center_spawned[1] += y_offset;
ui_block_translate(block, x_offset, y_offset);
if (U.pie_initial_timeout > 0)
block->pie_data.flags |= UI_PIE_INITIAL_DIRECTION;
}
ar->winrct.xmin = 0;
ar->winrct.xmax = winx;
ar->winrct.ymin = 0;
ar->winrct.ymax = winy;
ui_block_calculate_pie_segment(block, block->pie_data.pie_center_init);
/* lastly set the buttons at the center of the pie menu, ready for animation */
if (U.pie_animation_timeout > 0) {
for (but = block->buttons.first; but; but = but->next) {
if (but->pie_dir != UI_RADIAL_NONE) {
BLI_rctf_recenter(&but->rect, UNPACK2(block->pie_data.pie_center_spawned));
}
}
}
}
else {
/* clip block with window boundary */
ui_popup_block_clip(window, block);
/* the block and buttons were positioned in window space as in 2.4x, now
* these menu blocks are regions so we bring it back to region space.
* additionally we add some padding for the menu shadow or rounded menus */
ar->winrct.xmin = block->rect.xmin - width;
ar->winrct.xmax = block->rect.xmax + width;
ar->winrct.ymin = block->rect.ymin - width;
ar->winrct.ymax = block->rect.ymax + MENU_TOP;
ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
}
if (block_old) {
block->oldblock = block_old;
@@ -2353,6 +2406,12 @@ struct uiPopupMenu {
void *menu_arg;
};
struct uiPieMenu {
uiBlock *block_radial; /* radial block of the pie menu (more could be added later) */
uiLayout *layout;
int mx, my;
};
static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
{
uiBlock *block;
@@ -2526,7 +2585,7 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut
if (!but) {
handle->popup = true;
UI_add_popup_handlers(C, &window->modalhandlers, handle);
UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}
@@ -2588,7 +2647,7 @@ void uiPupMenuEnd(bContext *C, uiPopupMenu *pup)
menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup);
menu->popup = true;
UI_add_popup_handlers(C, &window->modalhandlers, menu);
UI_add_popup_handlers(C, &window->modalhandlers, menu, false);
WM_event_add_mousemove(C);
MEM_freeN(pup);
@@ -2599,6 +2658,175 @@ uiLayout *uiPupMenuLayout(uiPopupMenu *pup)
return pup->layout;
}
/*************************** Pie Menus ***************************************/
static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handle, void *arg_pie)
{
uiBlock *block;
uiPieMenu *pie = arg_pie;
int minwidth, width, height;
minwidth = 50;
block = pie->block_radial;
/* in some cases we create the block before the region,
* so we set it delayed here if necessary */
if (BLI_findindex(&handle->region->uiblocks, block) == -1)
uiBlockSetRegion(block, handle->region);
uiBlockLayoutResolve(block, &width, &height);
uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT);
block->minbounds = minwidth;
block->bounds = 1;
block->mx = 0;
block->my = 0;
block->bounds_type = UI_BLOCK_BOUNDS_PIE_CENTER;
block->pie_data.pie_center_spawned[0] = pie->mx;
block->pie_data.pie_center_spawned[1] = pie->my;
return pie->block_radial;
}
static float uiPieTitleWidth(const char *name, int icon)
{
return (UI_GetStringWidth(name) +
(UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
}
uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const wmEvent *event)
{
uiStyle *style = UI_GetStyleDraw();
uiPieMenu *pie = MEM_callocN(sizeof(uiPopupMenu), "pie menu");
pie->block_radial = uiBeginBlock(C, NULL, __func__, UI_EMBOSS);
/* may be useful later to allow spawning pies
* from old positions */
/* pie->block_radial->flag |= UI_BLOCK_POPUP_MEMORY; */
pie->block_radial->puphash = ui_popup_menu_hash(title);
pie->block_radial->flag |= UI_BLOCK_RADIAL;
pie->block_radial->pie_data.event = event->type;
pie->layout = uiBlockLayout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
pie->mx = event->x;
pie->my = event->y;
/* create title button */
if (title[0]) {
char titlestr[256];
int w;
if (icon) {
BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
w = uiPieTitleWidth(titlestr, icon);
uiDefIconTextBut(pie->block_radial, LABEL, 0, icon, titlestr, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
}
else {
w = uiPieTitleWidth(title, 0);
uiDefBut(pie->block_radial, LABEL, 0, title, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
}
}
return pie;
}
void uiPieMenuEnd(bContext *C, uiPieMenu *pie)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *menu;
menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PIE, pie);
menu->popup = true;
menu->towardstime = PIL_check_seconds_timer();
UI_add_popup_handlers(C, &window->modalhandlers, menu, true);
WM_event_add_mousemove(C);
MEM_freeN(pie);
}
uiLayout *uiPieMenuLayout(uiPieMenu *pie)
{
return pie->layout;
}
void uiPieMenuInvoke(struct bContext *C, const char *idname, const wmEvent *event)
{
uiPieMenu *pie;
uiLayout *layout;
Menu menu;
MenuType *mt = WM_menutype_find(idname, true);
if (mt == NULL) {
printf("%s: named menu \"%s\" not found\n", __func__, idname);
return;
}
if (mt->poll && mt->poll(C, mt) == 0)
return;
pie = uiPieMenuBegin(C, IFACE_(mt->label), ICON_NONE, event);
layout = uiPieMenuLayout(pie);
menu.layout = layout;
menu.type = mt;
if (G.debug & G_DEBUG_WM) {
printf("%s: opening menu \"%s\"\n", __func__, idname);
}
mt->draw(C, &menu);
uiPieMenuEnd(C, pie);
}
void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
const char *propname, const wmEvent *event)
{
uiPieMenu *pie;
uiLayout *layout;
pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event);
layout = uiPieMenuLayout(pie);
layout = uiLayoutRadial(layout);
uiItemsEnumO(layout, opname, propname);
uiPieMenuEnd(C, pie);
}
void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path,
const wmEvent *event)
{
PointerRNA ctx_ptr;
PointerRNA r_ptr;
PropertyRNA *r_prop;
uiPieMenu *pie;
uiLayout *layout;
RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr);
if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) {
return;
}
/* invalid property, only accept enums */
if (RNA_property_type(r_prop) != PROP_ENUM) {
BLI_assert(0);
return;
}
pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event);
layout = uiPieMenuLayout(pie);
layout = uiLayoutRadial(layout);
uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, NULL, 0);
uiPieMenuEnd(C, pie);
}
/*************************** Standard Popup Menus ****************************/
void uiPupMenuReports(bContext *C, ReportList *reports)
@@ -2695,7 +2923,7 @@ void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, const char *opn
handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
handle->opcontext = opcontext;
UI_add_popup_handlers(C, &window->modalhandlers, handle);
UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}
@@ -2718,7 +2946,7 @@ void uiPupBlockEx(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_f
handle->cancel_func = cancel_func;
// handle->opcontext = opcontext;
UI_add_popup_handlers(C, &window->modalhandlers, handle);
UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}

View File

@@ -1596,6 +1596,21 @@ static struct uiWidgetColors wcol_menu_back = {
25, -20
};
/* pie menus */
static struct uiWidgetColors wcol_pie_menu = {
{10, 10, 10, 200},
{25, 25, 25, 230},
{140, 140, 140, 255},
{45, 45, 45, 230},
{160, 160, 160, 255},
{255, 255, 255, 255},
1,
10, -10
};
/* tooltip color */
static struct uiWidgetColors wcol_tooltip = {
{0, 0, 0, 255},
@@ -1743,6 +1758,7 @@ void ui_widget_color_init(ThemeUI *tui)
tui->wcol_menu = wcol_menu;
tui->wcol_pulldown = wcol_pulldown;
tui->wcol_menu_back = wcol_menu_back;
tui->wcol_pie_menu = wcol_pie_menu;
tui->wcol_tooltip = wcol_tooltip;
tui->wcol_menu_item = wcol_menu_item;
tui->wcol_box = wcol_box;
@@ -1891,6 +1907,34 @@ static void widget_state_pulldown(uiWidgetType *wt, int state)
copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
}
/* special case, pie menu items */
static void widget_state_pie_menu_item(uiWidgetType *wt, int state)
{
wt->wcol = *(wt->wcol_theme);
/* active and disabled (not so common) */
if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f);
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
wt->wcol.inner[3] = 64;
}
/* regular disabled */
else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
}
/* regular active */
else if (state & UI_SELECT) {
copy_v4_v4_char(wt->wcol.outline, wt->wcol.inner_sel);
copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
}
else if (state & UI_ACTIVE) {
copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
}
}
/* special case, menu items */
static void widget_state_menu_item(uiWidgetType *wt, int state)
{
@@ -2973,6 +3017,29 @@ static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widgetbase_draw(&wtb, wcol);
}
static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
float rad;
float fac = but->block->pie_data.alphafac;
widget_init(&wtb);
wtb.emboss = 0;
rad = 0.5f * BLI_rcti_size_y(rect);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
wcol->inner[3] *= fac;
wcol->inner_sel[3] *= fac;
wcol->item[3] *= fac;
wcol->text[3] *= fac;
wcol->text_sel[3] *= fac;
wcol->outline[3] *= fac;
widgetbase_draw(&wtb, wcol);
}
static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
@@ -3291,6 +3358,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.wcol_theme = &btheme->tui.wcol_progress;
wt.custom = widget_progressbar;
break;
case UI_WTYPE_MENU_ITEM_RADIAL:
wt.wcol_theme = &btheme->tui.wcol_pie_menu;
wt.custom = widget_menu_radial_itembut;
wt.state = widget_state_pie_menu_item;
break;
}
return &wt;
@@ -3397,6 +3470,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
/* "nothing" */
wt = widget_type(UI_WTYPE_ICON);
}
else if (but->dt == UI_EMBOSSR) {
wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL);
}
else {
switch (but->type) {
@@ -3649,6 +3725,125 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
}
}
static void draw_disk_shaded(
float start, float angle,
float radius_int, float radius_ext, int subd,
const char col1[4], const char col2[4],
bool shaded)
{
const float radius_ext_scale = (0.5f / radius_ext); /* 1 / (2 * radius_ext) */
int i;
float s, c;
float y1, y2;
float fac;
unsigned char r_col[4];
glBegin(GL_TRIANGLE_STRIP);
s = sinf(start);
c = cosf(start);
y1 = s * radius_int;
y2 = s * radius_ext;
if (shaded) {
fac = (y1 + radius_ext) * radius_ext_scale;
round_box_shade_col4_r(r_col, col1, col2, fac);
glColor4ubv(r_col);
}
glVertex2f(c * radius_int, s * radius_int);
if (shaded) {
fac = (y2 + radius_ext) * radius_ext_scale;
round_box_shade_col4_r(r_col, col1, col2, fac);
glColor4ubv(r_col);
}
glVertex2f(c * radius_ext, s * radius_ext);
for (i = 1; i < subd; i++) {
float a;
a = start + ((i) / (float)(subd - 1)) * angle;
s = sinf(a);
c = cosf(a);
y1 = s * radius_int;
y2 = s * radius_ext;
if (shaded) {
fac = (y1 + radius_ext) * radius_ext_scale;
round_box_shade_col4_r(r_col, col1, col2, fac);
glColor4ubv(r_col);
}
glVertex2f(c * radius_int, s * radius_int);
if (shaded) {
fac = (y2 + radius_ext) * radius_ext_scale;
round_box_shade_col4_r(r_col, col1, col2, fac);
glColor4ubv(r_col);
}
glVertex2f(c * radius_ext, s * radius_ext);
}
glEnd();
}
void ui_draw_pie_center(uiBlock *block)
{
bTheme *btheme = UI_GetTheme();
float cx = block->pie_data.pie_center_spawned[0];
float cy = block->pie_data.pie_center_spawned[1];
float *pie_dir = block->pie_data.pie_dir;
float pie_radius_internal = U.pixelsize * U.pie_menu_threshold;
float pie_radius_external = U.pixelsize * (U.pie_menu_threshold + 7.0f);
int subd = 40;
float angle = atan2(pie_dir[1], pie_dir[0]);
float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? ((float)M_PI / 2.0f) : ((float)M_PI / 4.0f);
glPushMatrix();
glTranslatef(cx, cy, 0.0f);
glEnable(GL_BLEND);
if (btheme->tui.wcol_pie_menu.shaded) {
char col1[4], col2[4];
shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown);
draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, col1, col2, true);
}
else {
glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner);
draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, NULL, NULL, false);
}
if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) {
if (btheme->tui.wcol_pie_menu.shaded) {
char col1[4], col2[4];
shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner_sel, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown);
draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, col1, col2, true);
}
else {
glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner_sel);
draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, NULL, NULL, false);
}
}
glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.outline);
glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_internal, subd);
glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_external, subd);
glDisable(GL_BLEND);
glPopMatrix();
}
uiWidgetColors *ui_tooltip_get_theme(void)
{
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);

View File

@@ -2454,6 +2454,31 @@ void init_userdef_do_versions(void)
}
}
if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 4)) {
bTheme *btheme;
struct uiWidgetColors wcol_pie_menu = {
{10, 10, 10, 200},
{25, 25, 25, 230},
{140, 140, 140, 255},
{45, 45, 45, 230},
{160, 160, 160, 255},
{255, 255, 255, 255},
1,
10, -10
};
U.pie_menu_radius = 150;
U.pie_menu_threshold = 12;
U.pie_animation_timeout = 6;
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
btheme->tui.wcol_pie_menu = wcol_pie_menu;
}
}
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;

View File

@@ -61,6 +61,7 @@
#include "ED_space_api.h"
#include "ED_sound.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
#include "ED_mball.h"
#include "ED_logic.h"
#include "ED_clip.h"
@@ -130,8 +131,17 @@ void ED_spacetypes_init(void)
type->operatortypes();
}
/* Macros's must go last since they reference other operators
* maybe we'll need to have them go after python operators too? */
/* register internal render callbacks */
ED_render_internal_init();
}
void ED_spacemacros_init(void)
{
const ListBase *spacetypes;
SpaceType *type;
/* Macros's must go last since they reference other operators.
* We need to have them go after python operators too */
ED_operatormacros_armature();
ED_operatormacros_mesh();
ED_operatormacros_metaball();
@@ -152,9 +162,6 @@ void ED_spacetypes_init(void)
if (type->dropboxes)
type->dropboxes();
}
/* register internal render callbacks */
ED_render_internal_init();
}
/* called in wm.c */

View File

@@ -78,6 +78,7 @@
#include "ED_view3d.h"
#include "ED_sculpt.h"
#include "UI_resources.h"
#include "PIL_time.h" /* smoothview */
@@ -3550,13 +3551,13 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot)
/* ********************* Changing view operator ****************** */
static EnumPropertyItem prop_view_items[] = {
{RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View From the Left"},
{RV3D_VIEW_RIGHT, "RIGHT", ICON_TRIA_RIGHT, "Right", "View From the Right"},
{RV3D_VIEW_BOTTOM, "BOTTOM", ICON_TRIA_DOWN, "Bottom", "View From the Bottom"},
{RV3D_VIEW_TOP, "TOP", ICON_TRIA_UP, "Top", "View From the Top"},
{RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
{RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
{RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
{RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
{RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
{RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
{RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the Active Camera"},
{RV3D_VIEW_CAMERA, "CAMERA", ICON_CAMERA_DATA, "Camera", "View From the Active Camera"},
{0, NULL, 0, NULL, NULL}
};

View File

@@ -162,7 +162,7 @@ typedef struct ThemeUI {
uiWidgetColors wcol_radio, wcol_option, wcol_toggle;
uiWidgetColors wcol_num, wcol_numslider;
uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item, wcol_tooltip;
uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item;
uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item, wcol_pie_menu;
uiWidgetStateColors wcol_state;
@@ -534,6 +534,15 @@ typedef struct UserDef {
float fcu_inactive_alpha; /* opacity of inactive F-Curves in F-Curve Editor */
float pixelsize; /* private, set by GHOST, to multiply DPI with */
short pie_interaction_type; /* if keeping a pie menu spawn button pressed after this time, it turns into
* a drag/release pie menu */
short pie_initial_timeout; /* direction in the pie menu will always be calculated from the initial position
* within this time limit */
int pie_animation_timeout;
int pad2;
short pie_menu_radius; /* pie menu radius */
short pie_menu_threshold; /* pie menu distance from center before a direction is set */
struct WalkNavigation walk_navigation;
} UserDef;

View File

@@ -633,6 +633,7 @@ extern StructRNA RNA_TransformConstraint;
extern StructRNA RNA_TransformSequence;
extern StructRNA RNA_UILayout;
extern StructRNA RNA_UIList;
extern StructRNA RNA_UIPieMenu;
extern StructRNA RNA_UIPopupMenu;
extern StructRNA RNA_UVWarpModifier;
extern StructRNA RNA_UVProjectModifier;
@@ -794,6 +795,8 @@ void RNA_property_enum_items(struct bContext *C, PointerRNA *ptr, PropertyRNA *p
EnumPropertyItem **item, int *r_totitem, bool *r_free);
void RNA_property_enum_items_gettexted(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop,
EnumPropertyItem **r_item, int *r_totitem, bool *r_free);
void RNA_property_enum_items_gettexted_all(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop,
EnumPropertyItem **r_item, int *r_totitem, bool *r_free);
bool RNA_property_enum_value(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value);
bool RNA_property_enum_identifier(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **identifier);
bool RNA_property_enum_name(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name);

View File

@@ -1249,12 +1249,9 @@ void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, En
}
}
void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop,
EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
{
RNA_property_enum_items(C, ptr, prop, r_item, r_totitem, r_free);
#ifdef WITH_INTERNATIONAL
static void property_enum_translate(PropertyRNA *prop, EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
{
if (!(prop->flag & PROP_ENUM_NO_TRANSLATE)) {
int i;
@@ -1300,9 +1297,71 @@ void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA
*r_item = nitem;
}
}
#endif
void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop,
EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
{
RNA_property_enum_items(C, ptr, prop, r_item, r_totitem, r_free);
#ifdef WITH_INTERNATIONAL
property_enum_translate(prop, r_item, r_totitem, r_free);
#endif
}
void RNA_property_enum_items_gettexted_all(bContext *C, PointerRNA *ptr, PropertyRNA *prop,
EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
{
EnumPropertyRNA *eprop = (EnumPropertyRNA *)rna_ensure_property(prop);
int mem_size = sizeof(EnumPropertyItem) * (eprop->totitem + 1);
/* first return all items */
*r_free = true;
*r_item = MEM_mallocN(mem_size, "enum_gettext_all");
memcpy(*r_item, eprop->item, mem_size);
if (r_totitem)
*r_totitem = eprop->totitem;
if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
EnumPropertyItem *item;
int i;
bool free = false;
if (prop->flag & PROP_ENUM_NO_CONTEXT)
item = eprop->itemf(NULL, ptr, prop, &free);
else
item = eprop->itemf(C, ptr, prop, &free);
/* any callbacks returning NULL should be fixed */
BLI_assert(item != NULL);
for (i = 0; i < eprop->totitem; i++) {
bool exists = false;
int i_fixed;
/* items that do not exist on list are returned, but have their names/identifiers NULLed out */
for (i_fixed = 0; item[i_fixed].identifier; i_fixed++) {
if (STREQ(item[i_fixed].identifier, (*r_item)[i].identifier)) {
exists = true;
break;
}
}
if (!exists) {
(*r_item)[i].name = NULL;
(*r_item)[i].identifier = "";
}
}
if (free)
MEM_freeN(item);
}
#ifdef WITH_INTERNATIONAL
property_enum_translate(prop, r_item, r_totitem, r_free);
#endif
}
bool RNA_property_enum_value(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value)
{

View File

@@ -61,12 +61,12 @@
EnumPropertyItem object_mode_items[] = {
{OB_MODE_OBJECT, "OBJECT", ICON_OBJECT_DATAMODE, "Object Mode", ""},
{OB_MODE_EDIT, "EDIT", ICON_EDITMODE_HLT, "Edit Mode", ""},
{OB_MODE_POSE, "POSE", ICON_POSE_HLT, "Pose Mode", ""},
{OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt Mode", ""},
{OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""},
{OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
{OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
{OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""},
{OB_MODE_POSE, "POSE", ICON_POSE_HLT, "Pose Mode", ""},
{0, NULL, 0, NULL, NULL}
};

View File

@@ -1784,11 +1784,11 @@ static void rna_def_space_view3d(BlenderRNA *brna)
PropertyRNA *prop;
static EnumPropertyItem manipulators_items[] = {
{V3D_MANIP_TRANSLATE, "TRANSLATE", ICON_MAN_TRANS, "Manipulator Translate",
{V3D_MANIP_TRANSLATE, "TRANSLATE", ICON_MAN_TRANS, "Translate",
"Use the manipulator for movement transformations"},
{V3D_MANIP_ROTATE, "ROTATE", ICON_MAN_ROT, "Manipulator Rotate",
{V3D_MANIP_ROTATE, "ROTATE", ICON_MAN_ROT, "Rotate",
"Use the manipulator for rotation transformations"},
{V3D_MANIP_SCALE, "SCALE", ICON_MAN_SCALE, "Manipulator Scale",
{V3D_MANIP_SCALE, "SCALE", ICON_MAN_SCALE, "Scale",
"Use the manipulator for scale transformations"},
{0, NULL, 0, NULL, NULL}
};

View File

@@ -462,6 +462,13 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_float(func, "percentage", 0.0f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at", 0.0f, 1.0f);
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
/* radial/pie layout */
func = RNA_def_function(srna, "menu_pie", "uiLayoutRadial");
parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
RNA_def_function_return(func, parm);
RNA_def_function_ui_description(func, "Sublayout. Items placed in this sublayout are placed "
"in a radial fashion around the menu center)");
/* Icon of a rna pointer */
func = RNA_def_function(srna, "icon", "rna_ui_get_rnaptr_icon");
parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX);

View File

@@ -953,6 +953,12 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Menu Backdrop Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "wcol_pie_menu", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Pie Menu Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "wcol_tooltip", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Tooltip Colors", "");
@@ -3208,6 +3214,26 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sub Level Menu Open Delay",
"Time delay in 1/10 seconds before automatically opening sub level menus");
/* pie menus */
prop = RNA_def_property(srna, "pie_initial_timeout", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_text(prop, "Recenter Timeout",
"Pie menus will use the initial mouse position as center for this amount of time "
"(in 1/100ths of sec)");
prop = RNA_def_property(srna, "pie_animation_timeout", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_text(prop, "Animation Timeout",
"Time needed to fully animate the pie to unfolded state (in 1/100ths of sec)");
prop = RNA_def_property(srna, "pie_menu_radius", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_text(prop, "Radius", "Pie menu size in pixels");
prop = RNA_def_property(srna, "pie_menu_threshold", PROP_INT, PROP_PIXEL);
RNA_def_property_range(prop, 0, 1000);
RNA_def_property_ui_text(prop, "Threshold", "Distance from center needed before a selection can be made");
prop = RNA_def_property(srna, "use_quit_dialog", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_QUIT_PROMPT);
RNA_def_property_ui_text(prop, "Prompt Quit",

View File

@@ -594,6 +594,17 @@ static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr)
return rptr;
}
static PointerRNA rna_PieMenu_layout_get(PointerRNA *ptr)
{
struct uiPieMenu *pie = ptr->data;
uiLayout *layout = uiPieMenuLayout(pie);
PointerRNA rptr;
RNA_pointer_create(ptr->id.data, &RNA_UILayout, layout, &rptr);
return rptr;
}
static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
{
wmWindow *win = (wmWindow *)ptr->data;
@@ -1716,6 +1727,26 @@ static void rna_def_popupmenu(BlenderRNA *brna)
RNA_define_verify_sdna(1); /* not in sdna */
}
static void rna_def_piemenu(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "UIPieMenu", NULL);
RNA_def_struct_ui_text(srna, "PieMenu", "");
RNA_def_struct_sdna(srna, "uiPieMenu");
RNA_define_verify_sdna(0); /* not in sdna */
/* could wrap more, for now this is enough */
prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "UILayout");
RNA_def_property_pointer_funcs(prop, "rna_PieMenu_layout_get",
NULL, NULL, NULL);
RNA_define_verify_sdna(1); /* not in sdna */
}
static void rna_def_window(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2078,6 +2109,7 @@ void RNA_def_wm(BlenderRNA *brna)
rna_def_event(brna);
rna_def_timer(brna);
rna_def_popupmenu(brna);
rna_def_piemenu(brna);
rna_def_window(brna);
rna_def_windowmanager(brna);
rna_def_keyconfig(brna);

View File

@@ -310,6 +310,24 @@ static void rna_PupMenuEnd(bContext *C, PointerRNA *handle)
uiPupMenuEnd(C, handle->data);
}
/* pie menu wrapper */
static PointerRNA rna_PieMenuBegin(bContext *C, const char *title, int icon, PointerRNA *event)
{
PointerRNA r_ptr;
void *data;
data = (void *)uiPieMenuBegin(C, title, icon, event->data);
RNA_pointer_create(NULL, &RNA_UIPieMenu, data, &r_ptr);
return r_ptr;
}
static void rna_PieMenuEnd(bContext *C, PointerRNA *handle)
{
uiPieMenuEnd(C, handle->data);
}
#else
#define WM_GEN_INVOKE_EVENT (1 << 0)
@@ -461,6 +479,26 @@ void RNA_api_wm(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", "");
RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
/* wrap uiPieMenuBegin */
func = RNA_def_function(srna, "piemenu_begin__internal", "rna_PieMenuBegin");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "title", NULL, 0, "", "");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, icon_items);
parm = RNA_def_pointer(func, "event", "Event", "", "");
RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
/* return */
parm = RNA_def_pointer(func, "menu_pie", "UIPieMenu", "", "");
RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
RNA_def_function_return(func, parm);
/* wrap uiPieMenuEnd */
func = RNA_def_function(srna, "piemenu_end__internal", "rna_PieMenuEnd");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "menu", "UIPieMenu", "", "");
RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
}
void RNA_api_operator(StructRNA *srna)

View File

@@ -151,7 +151,7 @@ typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);
struct wmEventHandler *WM_event_add_ui_handler(
const struct bContext *C, ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
void *userdata);
void *userdata, const bool accept_dbl_click);
void WM_event_remove_ui_handler(
ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,

View File

@@ -64,6 +64,8 @@ wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, in
int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_menu(struct wmKeyMap *keymap, const char *idname, int type,
int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_menu_pie(struct wmKeyMap *keymap, const char *idname, int type,
int val, int modifier, int keymodifier, bool force_click);
bool WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
int WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, const int len);

View File

@@ -401,8 +401,12 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve
/* UI code doesn't handle return values - it just always returns break.
* to make the DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks */
if (event->type != LEFTMOUSE && event->val == KM_DBL_CLICK)
if (((handler->flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) &&
(event->type != LEFTMOUSE) &&
(event->val == KM_DBL_CLICK))
{
return WM_HANDLER_CONTINUE;
}
/* UI is quite aggressive with swallowing events, like scrollwheel */
/* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */
@@ -2563,7 +2567,7 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
wmEventHandler *WM_event_add_ui_handler(
const bContext *C, ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
void *userdata)
void *userdata, const bool accept_dbl_click)
{
wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event ui handler");
handler->ui_handle = ui_handle;
@@ -2580,6 +2584,9 @@ wmEventHandler *WM_event_add_ui_handler(
handler->ui_menu = NULL;
}
if (accept_dbl_click) {
handler->flag |= WM_HANDLER_ACCEPT_DBL_CLICK;
}
BLI_addhead(handlers, handler);

View File

@@ -187,6 +187,8 @@ void WM_init(bContext *C, int argc, const char **argv)
(void)argv; /* unused */
#endif
ED_spacemacros_init();
if (!G.background && !wm_start_with_console)
GHOST_toggleConsole(3);

View File

@@ -464,6 +464,14 @@ wmKeyMapItem *WM_keymap_add_menu(wmKeyMap *keymap, const char *idname, int type,
return kmi;
}
wmKeyMapItem *WM_keymap_add_menu_pie(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier, bool force_click)
{
wmKeyMapItem *kmi = WM_keymap_add_item(keymap, "WM_OT_call_menu_pie", type, val, modifier, keymodifier);
RNA_string_set(kmi->ptr, "name", idname);
RNA_boolean_set(kmi->ptr, "force_click", force_click);
return kmi;
}
bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
{
if (BLI_findindex(&keymap->items, kmi) != -1) {

View File

@@ -2049,6 +2049,41 @@ static void WM_OT_call_menu(wmOperatorType *ot)
RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
}
static int wm_call_pie_menu_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
char idname[BKE_ST_MAXNAME];
RNA_string_get(op->ptr, "name", idname);
uiPieMenuInvoke(C, idname, event);
return OPERATOR_CANCELLED;
}
static int wm_call_pie_menu_exec(bContext *C, wmOperator *op)
{
char idname[BKE_ST_MAXNAME];
RNA_string_get(op->ptr, "name", idname);
uiPieMenuInvoke(C, idname, CTX_wm_window(C)->eventstate);
return OPERATOR_CANCELLED;
}
static void WM_OT_call_menu_pie(wmOperatorType *ot)
{
ot->name = "Call Pie Menu";
ot->idname = "WM_OT_call_menu_pie";
ot->description = "Call (draw) a pre-defined pie menu";
ot->invoke = wm_call_pie_menu_invoke;
ot->exec = wm_call_pie_menu_exec;
ot->poll = WM_operator_winactive;
ot->flag = OPTYPE_INTERNAL;
RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
}
/* ************ window / screen operator definitions ************** */
/* this poll functions is needed in place of WM_operator_winactive
@@ -4427,6 +4462,7 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_splash);
WM_operatortype_append(WM_OT_search_menu);
WM_operatortype_append(WM_OT_call_menu);
WM_operatortype_append(WM_OT_call_menu_pie);
WM_operatortype_append(WM_OT_radial_control);
#if defined(WIN32)
WM_operatortype_append(WM_OT_console_toggle);

View File

@@ -81,8 +81,9 @@ enum {
/* handler flag */
enum {
WM_HANDLER_BLOCKING = 1, /* after this handler all others are ignored */
WM_HANDLER_DO_FREE = 2 /* handler tagged to be freed in wm_handlers_do() */
WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */
WM_HANDLER_DO_FREE = (1 << 1), /* handler tagged to be freed in wm_handlers_do() */
WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 2), /* handler accepts double key press events */
};
/* wm_event_system.c */

View File

@@ -622,6 +622,13 @@ struct wmKeyMap *WM_modalkeymap_add(struct wmKeyConfig *keyconf, const char *idn
struct uiPopupMenu *uiPupMenuBegin(struct bContext *C, const char *title, int icon) RET_NULL
void uiPupMenuEnd(struct bContext *C, struct uiPopupMenu *head) RET_NONE
struct uiLayout *uiPupMenuLayout(struct uiPopupMenu *head) RET_NULL
struct uiLayout *uiPieMenuLayout(struct uiPieMenu *pie) RET_NULL
void uiPieMenuInvoke(struct bContext *C, const char *idname, const struct wmEvent *event) RET_NONE
struct uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const struct wmEvent *event) RET_NULL
void uiPieMenuEnd(struct bContext *C, uiPieMenu *pie) RET_NONE
struct uiLayout *uiLayoutRadial(struct uiLayout *layout) RET_NULL
void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
const char *propname, const struct wmEvent *event) RET_NONE
/* RNA COLLADA dependency */
int collada_export(struct Scene *sce,