WIP: UI: Status Bar Keymaps When Idle #121059
|
@ -4067,7 +4067,8 @@ static uiBut *ui_def_but(uiBlock *block,
|
|||
float max,
|
||||
const char *tip)
|
||||
{
|
||||
BLI_assert(width >= 0 && height >= 0);
|
||||
/* Allow negative separators. */
|
||||
BLI_assert(width >= 0 && height >= 0 || (type == UI_BTYPE_SEPR));
|
||||
|
||||
if (type & UI_BUT_POIN_TYPES) { /* a pointer is required */
|
||||
if (poin == nullptr) {
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
#include "ED_object.hh"
|
||||
#include "ED_render.hh"
|
||||
#include "ED_screen.hh"
|
||||
#include "ED_screen_types.hh"
|
||||
#include "ED_undo.hh"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
|
@ -6307,6 +6308,60 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C)
|
|||
UI_block_emboss_set(block, previous_emboss);
|
||||
}
|
||||
|
||||
static wmKeyMapItem *keymapItem(bContext *C,
|
||||
wmWindowManager *wm,
|
||||
wmWindow *win,
|
||||
ScrArea *area,
|
||||
ARegion *region,
|
||||
short type,
|
||||
short val,
|
||||
uint8_t modifier)
|
||||
{
|
||||
wmEvent test_event = *win->eventstate;
|
||||
test_event.type = type;
|
||||
test_event.val = val;
|
||||
test_event.modifier = modifier;
|
||||
test_event.flag = (eWM_EventFlag)0;
|
||||
ListBase *handlers[] = {
|
||||
®ion->handlers,
|
||||
&area->handlers,
|
||||
&win->handlers,
|
||||
};
|
||||
|
||||
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
|
||||
if (!handlers[handler_index]) {
|
||||
continue;
|
||||
}
|
||||
wmKeyMapItem *kmi = WM_event_match_keymap_item_from_handlers(
|
||||
C, wm, win, handlers[handler_index], &test_event);
|
||||
if (kmi && !(kmi->flag & KMI_INACTIVE)) {
|
||||
return kmi;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool uiTemplateInputStatusAzone(uiLayout *layout, AZone *az, ARegion *region)
|
||||
{
|
||||
if (az->type == AZONE_AREA) {
|
||||
uiItemL(layout, IFACE_("Split (within area)"), ICON_MOUSE_LMB_DRAG);
|
||||
uiItemL(layout, IFACE_("Join (out of area)"), ICON_MOUSE_LMB_DRAG);
|
||||
uiItemL(layout, "", ICON_EVENT_SHIFT);
|
||||
uiItemL(layout, IFACE_("New window"), ICON_MOUSE_LMB_DRAG);
|
||||
uiItemL(layout, "", ICON_EVENT_CTRL);
|
||||
uiItemL(layout, IFACE_("Swap areas"), ICON_MOUSE_LMB_DRAG);
|
||||
return true;
|
||||
}
|
||||
if (az->type == AZONE_REGION) {
|
||||
uiItemL(layout,
|
||||
(region->visible) ? IFACE_("Resize region") : IFACE_("Show hidden region"),
|
||||
ICON_MOUSE_LMB_DRAG);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void uiTemplateInputStatus(uiLayout *layout, bContext *C)
|
||||
{
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
|
@ -6323,32 +6378,90 @@ void uiTemplateInputStatus(uiLayout *layout, bContext *C)
|
|||
}
|
||||
|
||||
/* Otherwise should cursor keymap status. */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
uiLayout *box = uiLayoutRow(layout, false);
|
||||
uiLayout *col = uiLayoutColumn(box, false);
|
||||
uiLayout *row = uiLayoutRow(col, true);
|
||||
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_LEFT);
|
||||
|
||||
const char *msg = CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT,
|
||||
WM_window_cursor_keymap_status_get(win, i, 0));
|
||||
const char *msg_drag = CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT,
|
||||
WM_window_cursor_keymap_status_get(win, i, 1));
|
||||
uiLayout *row = uiLayoutRow(layout, true);
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
ARegion *region = screen->active_region;
|
||||
ScrArea *area = nullptr;
|
||||
|
||||
if (msg || (msg_drag == nullptr)) {
|
||||
/* Icon and text separately are closer together with aligned layout. */
|
||||
uiItemL(row, "", (ICON_MOUSE_LMB + i));
|
||||
uiItemL(row, msg ? msg : "", ICON_NONE);
|
||||
if (region == nullptr) {
|
||||
/* Could be over an action zone. Separate PR? */
|
||||
LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
|
||||
LISTBASE_FOREACH (AZone *, az, &area_iter->actionzones) {
|
||||
if (BLI_rcti_isect_pt_v(&az->rect, win->eventstate->xy)) {
|
||||
region = az->region;
|
||||
area = area_iter;
|
||||
if (uiTemplateInputStatusAzone(row, az, region)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msg_drag) {
|
||||
uiItemL(row, "", (ICON_MOUSE_LMB_DRAG + i));
|
||||
uiItemL(row, msg_drag, ICON_NONE);
|
||||
}
|
||||
|
||||
/* Use trick with empty string to keep icons in same position. */
|
||||
row = uiLayoutRow(col, false);
|
||||
uiItemL(row, " ", ICON_NONE);
|
||||
}
|
||||
|
||||
if (!region) {
|
||||
/* Could be a separate PR to deal with edges. */
|
||||
uiItemL(row, "Resize", ICON_MOUSE_LMB_DRAG);
|
||||
uiItemL(row, "Options", ICON_MOUSE_RMB);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!area) {
|
||||
area = ED_area_find_under_cursor(C, SPACE_TYPE_ANY, win->eventstate->xy);
|
||||
}
|
||||
|
||||
if (area == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fallback to window for these region types. */
|
||||
if (ELEM(region->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
|
||||
region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
|
||||
}
|
||||
|
||||
ScrArea *save_area = CTX_wm_area(C);
|
||||
ARegion *save_region = CTX_wm_region(C);
|
||||
CTX_wm_window_set(C, win);
|
||||
CTX_wm_area_set(C, area);
|
||||
CTX_wm_region_set(C, region);
|
||||
|
||||
wmKeyMapItem *kmi;
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
blender::Set<std::string> op_names;
|
||||
uint8_t modifiers[] = {0, KM_SHIFT, KM_CTRL, KM_ALT, KM_OSKEY, KM_SHIFT | KM_CTRL};
|
||||
|
||||
for (int mod_index = 0; mod_index < ARRAY_SIZE(modifiers); mod_index++) {
|
||||
for (short button = LEFTMOUSE; button <= RIGHTMOUSE; button++) {
|
||||
for (short action = KM_PRESS; action <= KM_CLICK_DRAG; action++) {
|
||||
kmi = keymapItem(C, wm, win, area, region, button, action, modifiers[mod_index]);
|
||||
if (kmi) {
|
||||
wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
|
||||
const std::string operator_name = WM_operatortype_name(ot, kmi->ptr);
|
||||
std::string name = (ot) ? operator_name : kmi->idname;
|
||||
if (op_names.add(name)) {
|
||||
int icon_mod[4];
|
||||
int icon = UI_icon_from_keymap_item(kmi, icon_mod);
|
||||
for (int j = 0; j < ARRAY_SIZE(icon_mod) && icon_mod[j]; j++) {
|
||||
uiItemL(row, "", icon_mod[j]);
|
||||
}
|
||||
if (icon >= ICON_MOUSE_LMB && icon <= ICON_MOUSE_RMB) {
|
||||
uiItemS_ex(row, -0.5f);
|
||||
}
|
||||
uiItemL(row, "", icon);
|
||||
if (icon >= ICON_MOUSE_LMB && icon <= ICON_MOUSE_RMB) {
|
||||
uiItemS_ex(row, -0.7f);
|
||||
}
|
||||
uiItemL(row, name.c_str(), ICON_NONE);
|
||||
uiItemS_ex(row, 0.7f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CTX_wm_area_set(C, save_area);
|
||||
CTX_wm_region_set(C, save_region);
|
||||
}
|
||||
|
||||
void uiTemplateStatusInfo(uiLayout *layout, bContext *C)
|
||||
|
|
|
@ -973,6 +973,10 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
|
|||
screen->active_region = nullptr;
|
||||
}
|
||||
|
||||
if (region_prev != screen->active_region || !screen->active_region) {
|
||||
WM_window_status_area_tag_redraw(win);
|
||||
}
|
||||
|
||||
/* Check for redraw headers. */
|
||||
if (region_prev != screen->active_region) {
|
||||
|
||||
|
|
|
@ -397,8 +397,7 @@ typedef struct wmWindow {
|
|||
/** Custom drawing callbacks. */
|
||||
ListBase drawcalls;
|
||||
|
||||
/** Private runtime info to show text in the status bar. */
|
||||
void *cursor_keymap_status;
|
||||
void *_pad2;
|
||||
|
||||
/**
|
||||
* The time when the key is pressed in milliseconds (see #GHOST_GetEventTime).
|
||||
|
|
|
@ -1740,11 +1740,6 @@ void WM_event_tablet_data_default_set(wmTabletData *tablet_data);
|
|||
*/
|
||||
wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add);
|
||||
|
||||
const char *WM_window_cursor_keymap_status_get(const wmWindow *win,
|
||||
int button_index,
|
||||
int type_index);
|
||||
void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win);
|
||||
|
||||
void WM_window_status_area_tag_redraw(wmWindow *win);
|
||||
/**
|
||||
* Similar to #BKE_screen_area_map_find_area_xy and related functions,
|
||||
|
|
|
@ -171,7 +171,6 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
win->eventstate = nullptr;
|
||||
win->eventstate_prev_press_time_ms = 0;
|
||||
win->event_last_handled = nullptr;
|
||||
win->cursor_keymap_status = nullptr;
|
||||
#if defined(WIN32) || defined(__APPLE__)
|
||||
win->ime_data = nullptr;
|
||||
win->ime_data_is_composing = false;
|
||||
|
|
|
@ -726,14 +726,6 @@ void wm_event_do_notifiers(bContext *C)
|
|||
|
||||
RE_FreeUnusedGPUResources();
|
||||
|
||||
/* Status bar. */
|
||||
if (wm->winactive) {
|
||||
wmWindow *win = wm->winactive;
|
||||
CTX_wm_window_set(C, win);
|
||||
WM_window_cursor_keymap_status_refresh(C, win);
|
||||
CTX_wm_window_set(C, nullptr);
|
||||
}
|
||||
|
||||
/* Auto-run warning. */
|
||||
wm_test_autorun_warning(C);
|
||||
/* Deprecation warning. */
|
||||
|
@ -6142,52 +6134,6 @@ bool WM_event_match(const wmEvent *winevent, const wmKeyMapItem *kmi)
|
|||
* so only perform this on changing tools, space types, pressing different modifier keys... etc.
|
||||
* \{ */
|
||||
|
||||
/** State storage to detect changes between calls to refresh the information. */
|
||||
struct CursorKeymapInfo_State {
|
||||
uint8_t modifier;
|
||||
short space_type;
|
||||
short region_type;
|
||||
/** Never use, just compare memory for changes. */
|
||||
bToolRef tref;
|
||||
};
|
||||
|
||||
struct CursorKeymapInfo {
|
||||
/**
|
||||
* 0: Mouse button index.
|
||||
* 1: Event type (click/press, drag).
|
||||
* 2: Text.
|
||||
*/
|
||||
char text[3][2][128];
|
||||
wmEvent state_event;
|
||||
CursorKeymapInfo_State state;
|
||||
};
|
||||
|
||||
static void wm_event_cursor_store(CursorKeymapInfo_State *state,
|
||||
const wmEvent *event,
|
||||
short space_type,
|
||||
short region_type,
|
||||
const bToolRef *tref)
|
||||
{
|
||||
state->modifier = event->modifier;
|
||||
state->space_type = space_type;
|
||||
state->region_type = region_type;
|
||||
state->tref = tref ? *tref : bToolRef{};
|
||||
}
|
||||
|
||||
const char *WM_window_cursor_keymap_status_get(const wmWindow *win,
|
||||
int button_index,
|
||||
int type_index)
|
||||
{
|
||||
if (win->cursor_keymap_status != nullptr) {
|
||||
CursorKeymapInfo *cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
|
||||
const char *msg = cd->text[button_index][type_index];
|
||||
if (*msg) {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
|
||||
{
|
||||
if (screen->state == SCREENFULL) {
|
||||
|
@ -6212,157 +6158,6 @@ void WM_window_status_area_tag_redraw(wmWindow *win)
|
|||
}
|
||||
}
|
||||
|
||||
void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
|
||||
{
|
||||
bScreen *screen = WM_window_get_active_screen(win);
|
||||
ScrArea *area_statusbar = WM_window_status_area_find(win, screen);
|
||||
if (area_statusbar == nullptr) {
|
||||
MEM_SAFE_FREE(win->cursor_keymap_status);
|
||||
return;
|
||||
}
|
||||
|
||||
CursorKeymapInfo *cd;
|
||||
if (UNLIKELY(win->cursor_keymap_status == nullptr)) {
|
||||
win->cursor_keymap_status = MEM_callocN(sizeof(CursorKeymapInfo), __func__);
|
||||
}
|
||||
cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
|
||||
|
||||
/* Detect unchanged state (early exit). */
|
||||
if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now perform more comprehensive check,
|
||||
* still keep this fast since it happens on mouse-move. */
|
||||
CursorKeymapInfo cd_prev = *((CursorKeymapInfo *)win->cursor_keymap_status);
|
||||
cd->state_event = *win->eventstate;
|
||||
|
||||
/* Find active region and associated area. */
|
||||
ARegion *region = screen->active_region;
|
||||
if (region == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScrArea *area = nullptr;
|
||||
ED_screen_areas_iter (win, screen, area_iter) {
|
||||
if (BLI_findindex(&area_iter->regionbase, region) != -1) {
|
||||
area = area_iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (area == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Keep as-is. */
|
||||
if (ELEM(area->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) {
|
||||
return;
|
||||
}
|
||||
if (ELEM(region->regiontype,
|
||||
RGN_TYPE_HEADER,
|
||||
RGN_TYPE_TOOL_HEADER,
|
||||
RGN_TYPE_FOOTER,
|
||||
RGN_TYPE_ASSET_SHELF_HEADER,
|
||||
RGN_TYPE_TEMPORARY,
|
||||
RGN_TYPE_HUD))
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* Fallback to window. */
|
||||
if (ELEM(region->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
|
||||
region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
|
||||
}
|
||||
|
||||
/* Detect changes to the state. */
|
||||
{
|
||||
bToolRef *tref = nullptr;
|
||||
if ((region->regiontype == RGN_TYPE_WINDOW) &&
|
||||
((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK))
|
||||
{
|
||||
const Scene *scene = WM_window_get_active_scene(win);
|
||||
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
|
||||
WorkSpace *workspace = WM_window_get_active_workspace(win);
|
||||
bToolKey tkey{};
|
||||
tkey.space_type = area->spacetype;
|
||||
tkey.mode = WM_toolsystem_mode_from_spacetype(scene, view_layer, area, area->spacetype);
|
||||
tref = WM_toolsystem_ref_find(workspace, &tkey);
|
||||
}
|
||||
wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref);
|
||||
if (memcmp(&cd->state, &cd_prev.state, sizeof(cd->state)) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Changed context found, detect changes to key-map and refresh the status bar. */
|
||||
const struct {
|
||||
int button_index;
|
||||
int type_index; /* 0: press or click, 1: drag. */
|
||||
int event_type;
|
||||
int event_value;
|
||||
} event_data[] = {
|
||||
{0, 0, LEFTMOUSE, KM_PRESS},
|
||||
{0, 0, LEFTMOUSE, KM_CLICK},
|
||||
{0, 0, LEFTMOUSE, KM_CLICK_DRAG},
|
||||
|
||||
{1, 0, MIDDLEMOUSE, KM_PRESS},
|
||||
{1, 0, MIDDLEMOUSE, KM_CLICK},
|
||||
{1, 0, MIDDLEMOUSE, KM_CLICK_DRAG},
|
||||
|
||||
{2, 0, RIGHTMOUSE, KM_PRESS},
|
||||
{2, 0, RIGHTMOUSE, KM_CLICK},
|
||||
{2, 0, RIGHTMOUSE, KM_CLICK_DRAG},
|
||||
};
|
||||
|
||||
for (int button_index = 0; button_index < 3; button_index++) {
|
||||
cd->text[button_index][0][0] = '\0';
|
||||
cd->text[button_index][1][0] = '\0';
|
||||
}
|
||||
|
||||
CTX_wm_window_set(C, win);
|
||||
CTX_wm_area_set(C, area);
|
||||
CTX_wm_region_set(C, region);
|
||||
|
||||
ListBase *handlers[] = {
|
||||
®ion->handlers,
|
||||
&area->handlers,
|
||||
&win->handlers,
|
||||
};
|
||||
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
for (int data_index = 0; data_index < ARRAY_SIZE(event_data); data_index++) {
|
||||
const int button_index = event_data[data_index].button_index;
|
||||
const int type_index = event_data[data_index].type_index;
|
||||
if (cd->text[button_index][type_index][0] != 0) {
|
||||
continue;
|
||||
}
|
||||
wmEvent test_event = *win->eventstate;
|
||||
test_event.type = event_data[data_index].event_type;
|
||||
test_event.val = event_data[data_index].event_value;
|
||||
test_event.flag = (eWM_EventFlag)0;
|
||||
wm_eventemulation(&test_event, true);
|
||||
wmKeyMapItem *kmi = nullptr;
|
||||
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
|
||||
kmi = WM_event_match_keymap_item_from_handlers(
|
||||
C, wm, win, handlers[handler_index], &test_event);
|
||||
if (kmi) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (kmi) {
|
||||
wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
|
||||
const std::string operator_name = WM_operatortype_name(ot, kmi->ptr);
|
||||
const char *name = (ot) ? operator_name.c_str() : kmi->idname;
|
||||
STRNCPY(cd->text[button_index][type_index], name);
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(&cd_prev.text, &cd->text, sizeof(cd_prev.text)) != 0) {
|
||||
ED_area_tag_redraw(area_statusbar);
|
||||
}
|
||||
|
||||
CTX_wm_window_set(C, nullptr);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -276,10 +276,6 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
|
|||
WM_event_consecutive_data_free(win);
|
||||
}
|
||||
|
||||
if (win->cursor_keymap_status) {
|
||||
MEM_freeN(win->cursor_keymap_status);
|
||||
}
|
||||
|
||||
WM_gestures_free_all(win);
|
||||
|
||||
wm_event_free_all(win);
|
||||
|
|
Loading…
Reference in New Issue