Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/screen/screen_ops.c
| Show First 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | |||||
| #include "RNA_prototypes.h" | #include "RNA_prototypes.h" | ||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "UI_view2d.h" | #include "UI_view2d.h" | ||||
| #include "GPU_capabilities.h" | #include "GPU_capabilities.h" | ||||
| #include "wm_window.h" | |||||
| #include "screen_intern.h" /* own module include */ | #include "screen_intern.h" /* own module include */ | ||||
| #define KM_MODAL_CANCEL 1 | #define KM_MODAL_CANCEL 1 | ||||
| #define KM_MODAL_APPLY 2 | #define KM_MODAL_APPLY 2 | ||||
| #define KM_MODAL_SNAP_ON 3 | #define KM_MODAL_SNAP_ON 3 | ||||
| #define KM_MODAL_SNAP_OFF 4 | #define KM_MODAL_SNAP_OFF 4 | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| ▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | |||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) | static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| bScreen *screen = CTX_wm_screen(C); | bScreen *screen = CTX_wm_screen(C); | ||||
| sActionzoneData *sad = op->customdata; | sActionzoneData *sad = op->customdata; | ||||
| if (sad->modifier > 0 && sad->az->type == AZONE_AREA) { | |||||
| actionzone_apply(C, op, sad->az->type); | |||||
| actionzone_exit(op); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| switch (event->type) { | switch (event->type) { | ||||
| case MOUSEMOVE: { | case MOUSEMOVE: { | ||||
| const int delta_x = (event->xy[0] - sad->x); | const int delta_x = (event->xy[0] - sad->x); | ||||
| const int delta_y = (event->xy[1] - sad->y); | const int delta_y = (event->xy[1] - sad->y); | ||||
| /* Movement in dominant direction. */ | /* Movement in dominant direction. */ | ||||
| const int delta_max = max_ii(abs(delta_x), abs(delta_y)); | const int delta_max = max_ii(abs(delta_x), abs(delta_y)); | ||||
| Show All 26 Lines | |||||
| /* Have we dragged off the zone and are not on an edge? */ | /* Have we dragged off the zone and are not on an edge? */ | ||||
| if ((ED_area_actionzone_find_xy(sad->sa1, event->xy) != sad->az) && | if ((ED_area_actionzone_find_xy(sad->sa1, event->xy) != sad->az) && | ||||
| (screen_geom_area_map_find_active_scredge( | (screen_geom_area_map_find_active_scredge( | ||||
| AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) == NULL)) { | AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) == NULL)) { | ||||
| /* What area are we now in? */ | /* What area are we now in? */ | ||||
| ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); | ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); | ||||
| if (sad->modifier == 1) { | if (area == sad->sa1) { | ||||
| /* Duplicate area into new window. */ | |||||
| WM_cursor_set(win, WM_CURSOR_EDIT); | |||||
| is_gesture = (delta_max > area_threshold); | |||||
| } | |||||
| else if (sad->modifier == 2) { | |||||
| /* Swap areas. */ | |||||
| WM_cursor_set(win, WM_CURSOR_SWAP_AREA); | |||||
| is_gesture = true; | |||||
| } | |||||
| else if (area == sad->sa1) { | |||||
| /* Same area, so possible split. */ | /* Same area, so possible split. */ | ||||
| WM_cursor_set(win, | WM_cursor_set(win, | ||||
| SCREEN_DIR_IS_VERTICAL(sad->gesture_dir) ? WM_CURSOR_H_SPLIT : | SCREEN_DIR_IS_VERTICAL(sad->gesture_dir) ? WM_CURSOR_H_SPLIT : | ||||
| WM_CURSOR_V_SPLIT); | WM_CURSOR_V_SPLIT); | ||||
| is_gesture = (delta_max > split_threshold); | is_gesture = (delta_max > split_threshold); | ||||
| } | } | ||||
| else if (!area || area->global) { | else if (!area || area->global) { | ||||
| /* No area or Top bar or Status bar. */ | /* No area or Top bar or Status bar. */ | ||||
| ▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | |||||
| /* rna */ | /* rna */ | ||||
| RNA_def_int_vector( | RNA_def_int_vector( | ||||
| ot->srna, "cursor", 2, NULL, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX); | ot->srna, "cursor", 2, NULL, INT_MIN, INT_MAX, "Cursor", "", INT_MIN, INT_MAX); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Area Duplicate Operator | /** \name Area Docking Operator | ||||
| * | * | ||||
| * Create new window from area. | * Move areas into others, create new windows from areas. | ||||
| * \{ */ | * \{ */ | ||||
| /* operator callback */ | /* operator callback */ | ||||
| static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) | |||||
| typedef struct sAreaDockingData { | |||||
| ScrArea *sa1, *sa2; | |||||
| wmWindow *win1, *win2; | |||||
| eAreaDockTarget dock_target; | |||||
| void *target_callback; /* Call #screen_draw_dock_highlight. */ | |||||
| wmWindow *target_win; /* Which window is getting docking highlight. */ | |||||
| void *source_callback; /* area_docking_source_cb. */ | |||||
| } sAreaDockingData; | |||||
| static void area_docking_target_cb(const struct wmWindow *UNUSED(win), void *userdata) | |||||
| { | { | ||||
| ScrArea *area = CTX_wm_area(C); | const wmOperator *op = userdata; | ||||
| sAreaDockingData *dd = op->customdata; | |||||
| if (dd && dd->sa2) { | |||||
| screen_draw_dock_preview(dd->sa2, dd->dock_target); | |||||
| } | |||||
| } | |||||
| if (event && event->customdata) { | static void area_docking_source_cb(const struct wmWindow *UNUSED(win), void *userdata) | ||||
| sActionzoneData *sad = event->customdata; | { | ||||
| if (sad == NULL) { | const wmOperator *op = userdata; | ||||
| return OPERATOR_PASS_THROUGH; | sAreaDockingData *dd = op->customdata; | ||||
| if (dd && dd->sa1) { | |||||
| float outline[4] = {1.0f, 1.0f, 1.0f, 0.4f}; | |||||
| UI_draw_roundbox_corner_set(UI_CNR_ALL); | |||||
| rctf rect; | |||||
| BLI_rctf_rcti_copy(&rect, &dd->sa1->totrct); | |||||
| UI_draw_roundbox_4fv_ex(&rect, NULL, NULL, 1.0f, outline, U.pixelsize, 7 * U.pixelsize); | |||||
| } | |||||
| } | |||||
| static void area_docking_cb_window(sAreaDockingData *dd, wmOperator *op) | |||||
| { | |||||
| if (dd->sa2 && dd->win2 != dd->target_win) { | |||||
| /* Change of highlight window. */ | |||||
| if (dd->target_callback) { | |||||
| WM_draw_cb_exit(dd->target_win, dd->target_callback); | |||||
| /* Refresh the entire window. */ | |||||
| ED_screen_areas_iter (dd->target_win, WM_window_get_active_screen(dd->target_win), area) { | |||||
| ED_area_tag_redraw(area); | |||||
| } | |||||
| } | } | ||||
| area = sad->sa1; | dd->target_win = dd->win2; | ||||
| dd->target_callback = WM_draw_cb_activate(dd->target_win, area_docking_target_cb, op); | |||||
| } | } | ||||
| } | |||||
| static void area_docking_exit(bContext *C, wmOperator *op) | |||||
| { | |||||
| sAreaDockingData *dd = (sAreaDockingData *)op->customdata; | |||||
| if (dd && dd->target_callback) { | |||||
| WM_draw_cb_exit(dd->target_win, dd->target_callback); | |||||
| } | |||||
| WM_draw_cb_exit(dd->win1, dd->source_callback); | |||||
| WM_cursor_modal_restore(CTX_wm_window(C)); | |||||
| MEM_SAFE_FREE(op->customdata); | |||||
| } | |||||
| static bool area_docking_float(bContext *C, ScrArea *area, const int x, const int y) | |||||
| { | |||||
| /* Create new window. No need to set space_type since it will be copied over. */ | /* Create new window. No need to set space_type since it will be copied over. */ | ||||
| wmWindow *newwin = WM_window_open(C, | wmWindow *newwin = WM_window_open(C, | ||||
| "Blender", | "Blender", | ||||
| area->totrct.xmin, | x, | ||||
| area->totrct.ymin, | y, | ||||
| area->winx, | area->winx, | ||||
| area->winy, | area->winy, | ||||
| SPACE_EMPTY, | SPACE_EMPTY, | ||||
| false, | false, | ||||
| false, | false, | ||||
| false, | false, | ||||
| WIN_ALIGN_ABSOLUTE); | WIN_ALIGN_ABSOLUTE); | ||||
| if (newwin) { | if (newwin) { | ||||
| /* copy area to new screen */ | /* copy area to new screen */ | ||||
| bScreen *newsc = WM_window_get_active_screen(newwin); | bScreen *newsc = WM_window_get_active_screen(newwin); | ||||
| ED_area_data_copy((ScrArea *)newsc->areabase.first, area, true); | ED_area_data_copy((ScrArea *)newsc->areabase.first, area, true); | ||||
| ED_area_tag_redraw((ScrArea *)newsc->areabase.first); | ED_area_tag_redraw((ScrArea *)newsc->areabase.first); | ||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /* screen, areas init */ | static int area_docking_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); | { | ||||
| sActionzoneData *sad = event->customdata; | |||||
| if (sad == NULL || sad->sa1 == NULL) { | |||||
| return OPERATOR_PASS_THROUGH; | |||||
| } | |||||
| sAreaDockingData *dd = MEM_callocN(sizeof(sAreaDockingData), "sAreaDockingData"); | |||||
| dd->sa1 = sad->sa1; | |||||
| dd->win1 = WM_window_from_area(CTX_wm_manager(C), sad->sa1); | |||||
| dd->sa2 = NULL; | |||||
| dd->win2 = NULL; | |||||
| dd->target_win = dd->win1; | |||||
| dd->target_callback = WM_draw_cb_activate(dd->target_win, area_docking_target_cb, op); | |||||
| dd->source_callback = WM_draw_cb_activate(dd->win1, area_docking_source_cb, op); | |||||
| op->customdata = dd; | |||||
| /* add modal handler */ | |||||
| WM_event_add_modal_handler(C, op); | |||||
| return OPERATOR_RUNNING_MODAL; | |||||
| } | |||||
| static int area_docking_cursor(sAreaDockingData *dd, const wmEvent *event) | |||||
| { | |||||
| if (!dd->sa2) { | |||||
| /* Mouse outside window, so can open new window. */ | |||||
| if (event->xy[0] < 0 || event->xy[0] > dd->win1->sizex || event->xy[1] < 1 || | |||||
| event->xy[1] > dd->win1->sizey) { | |||||
| return WM_CURSOR_PICK_AREA; | |||||
| } | |||||
| return WM_CURSOR_STOP; | |||||
| } | |||||
| else if (dd->sa1 && dd->sa1 == dd->sa2) { | |||||
| return WM_CURSOR_PICK_AREA; | |||||
| } | |||||
| else if (dd->dock_target == DOCKING_CENTER) { | |||||
| return WM_CURSOR_HAND; | |||||
| } | |||||
| return WM_CURSOR_DEFAULT; | |||||
| } | |||||
| static eAreaDockTarget area_docking_target(sAreaDockingData *dd, const int xy[2]) | |||||
| { | |||||
| if (!dd->sa2 || !dd->win2 || dd->sa1 == dd->sa2) { | |||||
| return DOCKING_NONE; | |||||
| } | |||||
| /* Convert to local coordinates in sa2. */ | |||||
| int x = xy[0] + dd->win1->posx - dd->win2->posx - dd->sa2->totrct.xmin; | |||||
| int y = xy[1] + dd->win1->posy - dd->win2->posy - dd->sa2->totrct.ymin; | |||||
| int min = (10 * HEADERY * U.dpi_fac); /* Small enough to get limited choices. */ | |||||
| /* Are we in the center? Or somewhere in a small area? */ | |||||
| if ((dd->sa2->winx < min && dd->sa2->winy < min) || | |||||
| (x > (dd->sa2->winx * 0.4f) && x < (dd->sa2->winx * 0.6f) && y > (dd->sa2->winy * 0.4f) && | |||||
| y < (dd->sa2->winy * 0.6f))) { | |||||
| return DOCKING_CENTER; | |||||
| } | |||||
| /* if the area is narrow then there are only two docking targets. */ | |||||
| if (dd->sa2->winx < min) { | |||||
| return (y < dd->sa2->winy / 2) ? DOCKING_BOTTOM : DOCKING_TOP; | |||||
| } | |||||
| if (dd->sa2->winy < min) { | |||||
| return (x < dd->sa2->winx / 2) ? DOCKING_LEFT : DOCKING_RIGHT; | |||||
| } | |||||
| /* Area is large enough for four docking targets. */ | |||||
| float area_ratio = (float)dd->sa2->winx / (float)dd->sa2->winy; | |||||
| bool TL = (area_ratio > (float)x / (float)(y + 1)); | |||||
| bool BL = (area_ratio > (float)x / (float)(dd->sa2->winy - y + 1)); | |||||
campbellbarton: can be `static` | |||||
| if (TL && !BL) { | |||||
| return DOCKING_TOP; | |||||
| } | |||||
| else if (!TL && BL) { | |||||
| return DOCKING_BOTTOM; | |||||
| } | |||||
| else if (TL && BL) { | |||||
| return DOCKING_LEFT; | |||||
| } | } | ||||
| else { | else { | ||||
| BKE_report(op->reports, RPT_ERROR, "Failed to open window!"); | return DOCKING_RIGHT; | ||||
| } | } | ||||
| } | |||||
| if (event && event->customdata) { | static void area_docking_dock(bContext *C, sAreaDockingData *dd) | ||||
| actionzone_exit(op); | { | ||||
| int offset1; | |||||
| int offset2; | |||||
| area_getoffsets(dd->sa1, dd->sa2, area_getorientation(dd->sa1, dd->sa2), &offset1, &offset2); | |||||
| bool aligned_neighbors = (offset1 == 0 && offset2 == 0); | |||||
| if (!(dd->dock_target == DOCKING_CENTER)) { | |||||
| eScreenAxis dir = (ELEM(dd->dock_target, DOCKING_LEFT, DOCKING_RIGHT)) ? SCREEN_AXIS_V : | |||||
| SCREEN_AXIS_H; | |||||
| float fac = (ELEM(dd->dock_target, DOCKING_LEFT, DOCKING_BOTTOM)) ? 0.4999f : 0.5001f; | |||||
| dd->sa2 = area_split(dd->win2, WM_window_get_active_screen(dd->win2), dd->sa2, dir, fac, true); | |||||
| } | |||||
| if (!aligned_neighbors || !screen_area_join(C, CTX_wm_screen(C), dd->sa1, dd->sa2)) { | |||||
| ED_area_swapspace(C, dd->sa2, dd->sa1); | |||||
| if (BLI_listbase_is_single(&WM_window_get_active_screen(dd->win1)->areabase) && | |||||
| BLI_listbase_is_empty(&dd->win1->global_areas.areabase)) { | |||||
| /* We are closing the last area of a non-main window, so close window. */ | |||||
| wm_window_close(C, CTX_wm_manager(C), dd->win1); | |||||
| dd->win1 = NULL; | |||||
| } | |||||
| else { | |||||
| screen_area_close(C, CTX_wm_screen(C), dd->sa1); | |||||
| } | |||||
| } | |||||
| if (dd && dd->sa2 == CTX_wm_area(C)) { | |||||
| CTX_wm_area_set(C, NULL); | |||||
| CTX_wm_region_set(C, NULL); | |||||
| } | |||||
Not Done Inline Actionswarning: ‘static’ is not at beginning of declaration [-Wold-style-declaration]. campbellbarton: `warning: ‘static’ is not at beginning of declaration [-Wold-style-declaration]`. | |||||
| } | |||||
| static void area_docking_update_data(bContext *C, sAreaDockingData *dd, const wmEvent *event) | |||||
| { | |||||
| dd->sa2 = ED_area_find_under_cursor(C, SPACE_TYPE_ANY, event->xy); | |||||
| dd->win2 = WM_window_from_area(CTX_wm_manager(C), dd->sa2); | |||||
| dd->dock_target = area_docking_target(dd, event->xy); | |||||
| } | |||||
| static int area_docking_modal(bContext *C, wmOperator *op, const wmEvent *event) | |||||
| { | |||||
| sAreaDockingData *dd = op->customdata; | |||||
| if (!dd) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| switch (event->type) { | |||||
| case MOUSEMOVE: | |||||
| /* Second area to swap with. */ | |||||
| area_docking_update_data(C, dd, event); | |||||
| area_docking_cb_window(dd, op); | |||||
| WM_cursor_set(dd->win1, area_docking_cursor(dd, event)); | |||||
| WM_event_add_notifier(C, NC_WINDOW, NULL); | |||||
| break; | |||||
| case LEFTMOUSE: /* release LMB */ | |||||
| if (event->val == KM_RELEASE) { | |||||
| area_docking_update_data(C, dd, event); | |||||
| area_docking_cb_window(dd, op); | |||||
| ED_area_tag_redraw(dd->sa1); | |||||
| ED_area_tag_redraw(dd->sa2); | |||||
| if (dd->sa1 && (!dd->sa2 || dd->sa1 == dd->sa2)) { | |||||
| /* Break out into new window if we are really outside the source window bounds. */ | |||||
| if ((dd->sa1 == dd->sa2) || (event->xy[0] < 0 || event->xy[0] > dd->win1->sizex || | |||||
| event->xy[1] < 1 || event->xy[1] > dd->win1->sizey)) { | |||||
| /* We have to clear handlers or we get an error in wm_gizmomap_modal_get. */ | |||||
| WM_event_modal_handler_region_replace(dd->win1, CTX_wm_region(C), NULL); | |||||
| bScreen *screen = CTX_wm_screen(C); | |||||
| area_docking_float(C, dd->sa1, event->xy[0], event->xy[1] - dd->sa1->winy); | |||||
| screen_area_close(C, screen, dd->sa1); | |||||
| } | |||||
| } | |||||
| else if (dd->dock_target != DOCKING_NONE) { | |||||
| area_docking_dock(C, dd); | |||||
| } | |||||
| else { | |||||
| area_docking_exit(C, op); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); | |||||
| if (dd->win1) { | |||||
| area_docking_exit(C, op); | |||||
| } | |||||
| /* Update preview thumbnail */ | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| break; | |||||
| case EVT_ESCKEY: | |||||
| area_docking_exit(C, op); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | } | ||||
| return OPERATOR_RUNNING_MODAL; | |||||
| } | |||||
| return newwin ? OPERATOR_FINISHED : OPERATOR_CANCELLED; | static int area_dupli_exec(bContext *C, wmOperator *op) | ||||
| { | |||||
| ScrArea *area = CTX_wm_area(C); | |||||
| area_docking_float(C, area, area->totrct.xmin, area->totrct.ymin); | |||||
| WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | } | ||||
| static void SCREEN_OT_area_dupli(wmOperatorType *ot) | static void SCREEN_OT_area_dupli(wmOperatorType *ot) | ||||
| { | { | ||||
| ot->name = "Duplicate Area into New Window"; | ot->name = "Duplicate Area into New Window"; | ||||
| ot->description = "Duplicate selected area into new window"; | ot->description = "Duplicate selected area into new window"; | ||||
| ot->idname = "SCREEN_OT_area_dupli"; | ot->idname = "SCREEN_OT_area_dupli"; | ||||
| ot->invoke = area_dupli_invoke; | ot->invoke = area_docking_invoke; | ||||
| ot->modal = area_docking_modal; | |||||
| ot->exec = area_dupli_exec; | |||||
| ot->cancel = area_docking_exit; | |||||
| ot->poll = ED_operator_areaactive; | ot->poll = ED_operator_areaactive; | ||||
| ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Area Close Operator | /** \name Area Close Operator | ||||
| * | * | ||||
| * Close selected area, replace by expanding a neighbor | * Close selected area, replace by expanding a neighbor | ||||
| ▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | |||||
| NULL, | NULL, | ||||
| WM_OP_INVOKE_DEFAULT, | WM_OP_INVOKE_DEFAULT, | ||||
| 0, | 0, | ||||
| &ptr); | &ptr); | ||||
| RNA_boolean_set(&ptr, "use_hide_panels", true); | RNA_boolean_set(&ptr, "use_hide_panels", true); | ||||
| } | } | ||||
| } | } | ||||
| uiItemO(layout, NULL, ICON_NONE, "SCREEN_OT_area_dupli"); | uiItemFullO(layout, "SCREEN_OT_area_dupli", NULL, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); | ||||
| uiItemS(layout); | uiItemS(layout); | ||||
| uiItemO(layout, NULL, ICON_NONE, "SCREEN_OT_area_close"); | uiItemO(layout, NULL, ICON_NONE, "SCREEN_OT_area_close"); | ||||
| } | } | ||||
| void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) | void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg)) | ||||
| { | { | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| ▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines | |||||
can be static