Page MenuHome

Cleanup: use enum for screen direction variables
ClosedPublic

Authored by Campbell Barton (campbellbarton) on May 13 2021, 7:44 AM.

Details

Summary

The term direction was used in 3 different ways in screen editing code,
making it hard to follow:

  • 0-3 for as magic numbers mapped to [west,north,east,south].
  • h, v characters for [horizontal,vertical] axes.
  • Cycle direction SPACE_CONTEXT_CYCLE_PREV, SPACE_CONTEXT_CYCLE_NEXT

The following changes have been made:

  • Add eScreenDir for [west,north,east,south], use variable name dir.
  • Add eScreenAxis for [horizontal,vertical] values, use variable name dir_axis.
  • Add eScreenCycle for existing enum SPACE_CONTEXT_CYCLE_{PREV/NEXT}.
  • Add macros SCREEN_DIR_IS_VERTICAL(dir), SCREEN_DIR_IS_HORIZONTAL(dir). Replacing ELEM(dir, 1, 3), ELEM(dir, 0, 2).
  • Move ED_screen_draw_join_highlight, ED_screen_draw_split_preview to screen_intern.h.

Notes:

  • Some of these choices are arbitrary, we could even make these enums more generic, sharing them between other files.
  • The removal of h and v could be extended to view2d code where they're currently used.
  • I used the term dir_axis for eScreenAxis instead of axis since the operator settings use "direction" as a property name, and there are existing uses of the variable axis in this code X=0, Y=1.

Diff Detail

Repository
rB Blender

Event Timeline

Campbell Barton (campbellbarton) requested review of this revision.May 13 2021, 7:44 AM
Campbell Barton (campbellbarton) created this revision.
Campbell Barton (campbellbarton) retitled this revision from Use enum types for screen direction variables to Cleanup: use enum for screen direction variables.May 13 2021, 7:56 AM
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)

This would be awesome, and a great time to do this. I have thought about this in the past but it got a bit more complex than I'd like. My attempts usually started something like this:

typedef enum eScreenDir {
  SCREEN_DIR_NONE = 0, /* Unset, unknown, or invalid. */
  SCREEN_DIR_W = (1 << 0), /* To West/Left. */
  SCREEN_DIR_N = (1 << 1), /* To North/Up. */
  SCREEN_DIR_E = (1 << 2), /* To East/Right. */
  SCREEN_DIR_S = (1 << 3), /* To South/Down. */
  SCREEN_AXIS_H = SCREEN_DIR_W | SCREEN_DIR_E,
  SCREEN_AXIS_V = SCREEN_DIR_N | SCREEN_DIR_S
} eScreenDir;

Using zero for no direction seemed to fit well, and using bits allowed simplification of all the ELEM(dir, SCREEN_DIR_N, SCREEN_DIR_S) all over the place, and also gets rid of the 'h' and 'v' char values.

But I'd usually give up on the attempts because I found it difficult to find all the usages of these directions all over. I normally want one patch to fix everything and not have to go back and incrementally fix what I missed.

Since the current uses of the enum don't mix directions, I'd rather this be a separate enum/flag, e.g. SCREEN_DIR_MASK_W = (1 << SCREEN_DIR_W).

Then it's clear when multiple directions need to be checked.

@Campbell Barton (campbellbarton) - Then it's clear when multiple directions need to be checked.

Or maybe like this. I just like the idea of getting rid of the "v/h" char values.

typedef enum eScreenDir {
  SCREEN_DIR_NONE = 0, /* Unset, unknown, or invalid. */
  SCREEN_DIR_W = (1 << 0), /* To West/Left. */
  SCREEN_DIR_N = (1 << 1), /* To North/Up. */
  SCREEN_DIR_E = (1 << 2), /* To East/Right. */
  SCREEN_DIR_S = (1 << 3), /* To South/Down. */
} eScreenDir;

typedef enum eScreenAxis {
  SCREEN_AXIS_NONE = 0,
  SCREEN_AXIS_H = SCREEN_DIR_W | SCREEN_DIR_E, /* Horizontal */
  SCREEN_AXIS_V = SCREEN_DIR_N | SCREEN_DIR_S, /* Vertical. */
} eScreenAxis;

#define SCREEN_DIR_IS_V(dir) (SCREEN_AXIS_V & dir)
#define SCREEN_DIR_IS_H(dir) (SCREEN_AXIS_H & dir)

The problem with making these flags is any code that uses them might check if (dir & SCREEN_DIR_W) {...} instead of if (dir == SCREEN_DIR_W) {...}.
Then anyone changing the code might reasonably mix direction flags together and pass them to functions.

Since the existing logic doesn't gain much/anything from mixing these as flags, making them into flags adds ambiguity where the current usage is strict.

We could do this:

typedef enum eScreenAxis {
  SCREEN_AXIS_H = (1 << SCREEN_DIR_W) | (1 << SCREEN_DIR_E), /* Horizontal */
  SCREEN_AXIS_V = (1 << SCREEN_DIR_N) | (1 << SCREEN_DIR_S), /* Vertical. */
} eScreenAxis;

#define SCREEN_DIR_IS_V(dir) (SCREEN_AXIS_V & (1 << (dir)))
#define SCREEN_DIR_IS_H(dir) (SCREEN_AXIS_H & (1 << (dir)))

Although comparing directly with the enum is less error prone as it will give useful warning messages if an incompatible enum is used.

Julian Eisel (Severin) accepted this revision.EditedMay 14 2021, 2:47 PM

I don't see an issue with just having multiple enum definitions. E.g. if we need a version of an enum that uses bitflags, just add a new enum next to the existing one. And I would avoid trying to have combined enums. I rather have a bunch of small but clear & safe enums, even if there's some redundancy within them.
With C++ we could have richer enums with overloaded operators (e.g. the | or & operators) that are still type safe. But that's for a different day.

So this current patch is fine IMHO.

source/blender/editors/screen/screen_ops.c
5434

I don't really see the point in changing this from direction to dir_cycle. For me the former is more clear and just rehashing that this cycles doesn't add much to the context in my mind.

This revision is now accepted and ready to land.May 14 2021, 2:47 PM
Campbell Barton (campbellbarton) edited the summary of this revision. (Show Details)
  • Rename dir_cycle back to direction based on feedback.
Campbell Barton (campbellbarton) added inline comments.
source/blender/editors/screen/screen_ops.c
5434

Made the change before adding a type for eScreenCycle, since it's a named type - agree it's not such a useful distinction.