Blender V4.5
space_console.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdio>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "BLI_listbase.h"
15#include "BLI_string.h"
16
17#include "BKE_context.hh"
18#include "BKE_screen.hh"
19
20#include "ED_screen.hh"
21#include "ED_space_api.hh"
22
23#include "RNA_access.hh"
24#include "RNA_path.hh"
25
26#include "WM_api.hh"
27#include "WM_types.hh"
28
29#include "UI_resources.hh"
30#include "UI_view2d.hh"
31
32#include "BLO_read_write.hh"
33
34#include "console_intern.hh" /* own include */
35
36/* ******************** default callbacks for console space ***************** */
37
38static SpaceLink *console_create(const ScrArea * /*area*/, const Scene * /*scene*/)
39{
40 ARegion *region;
41 SpaceConsole *sconsole;
42
43 sconsole = MEM_callocN<SpaceConsole>("initconsole");
44 sconsole->spacetype = SPACE_CONSOLE;
45
46 sconsole->lheight = 14;
47
48 /* header */
49 region = BKE_area_region_new();
50
51 BLI_addtail(&sconsole->regionbase, region);
54
55 /* main region */
56 region = BKE_area_region_new();
57
58 BLI_addtail(&sconsole->regionbase, region);
60
61 /* keep in sync with info */
63 region->v2d.align |= V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y; /* align bottom left */
64 region->v2d.keepofs |= V2D_LOCKOFS_X;
67 region->v2d.minzoom = region->v2d.maxzoom = 1.0f;
68
69 /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
70 // region->v2d.keepzoom = (V2D_KEEPASPECT|V2D_LIMITZOOM);
71
72 return (SpaceLink *)sconsole;
73}
74
75/* Doesn't free the space-link itself. */
76static void console_free(SpaceLink *sl)
77{
78 SpaceConsole *sc = (SpaceConsole *)sl;
79
80 while (sc->scrollback.first) {
81 console_scrollback_free(sc, static_cast<ConsoleLine *>(sc->scrollback.first));
82 }
83
84 while (sc->history.first) {
85 console_history_free(sc, static_cast<ConsoleLine *>(sc->history.first));
86 }
87}
88
89/* spacetype; init callback */
90static void console_init(wmWindowManager * /*wm*/, ScrArea * /*area*/) {}
91
93{
94 SpaceConsole *sconsolen = static_cast<SpaceConsole *>(MEM_dupallocN(sl));
95
96 /* clear or remove stuff from old */
97
98 /* TODO: duplicate?, then we also need to duplicate the py namespace. */
99 BLI_listbase_clear(&sconsolen->scrollback);
100 BLI_listbase_clear(&sconsolen->history);
101
102 return (SpaceLink *)sconsolen;
103}
104
105/* add handlers, stuff you only do once or on area/region changes */
107{
108 wmKeyMap *keymap;
109 ListBase *lb;
110
111 const float prev_y_min = region->v2d.cur.ymin; /* so re-sizing keeps the cursor visible */
112
113 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_CUSTOM, region->winx, region->winy);
114
115 /* always keep the bottom part of the view aligned, less annoying */
116 if (prev_y_min != region->v2d.cur.ymin) {
117 const float cur_y_range = BLI_rctf_size_y(&region->v2d.cur);
118 region->v2d.cur.ymin = prev_y_min;
119 region->v2d.cur.ymax = prev_y_min + cur_y_range;
120 }
121
122 /* own keymap */
124 WM_event_add_keymap_handler_v2d_mask(&region->runtime->handlers, keymap);
125
126 /* Include after "Console" so cursor motion keys such as "Home" isn't overridden. */
127 keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", SPACE_EMPTY, RGN_TYPE_WINDOW);
128 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
129
130 /* add drop boxes */
132
133 WM_event_add_dropbox_handler(&region->runtime->handlers, lb);
134}
135
136/* same as 'text_cursor' */
137static void console_cursor(wmWindow *win, ScrArea * /*area*/, ARegion *region)
138{
139 int wmcursor = WM_CURSOR_TEXT_EDIT;
140 const wmEvent *event = win->eventstate;
141 if (UI_view2d_mouse_in_scrollers(region, &region->v2d, event->xy)) {
142 wmcursor = WM_CURSOR_DEFAULT;
143 }
144
145 WM_cursor_set(win, wmcursor);
146}
147
148/* ************* dropboxes ************* */
149
150static bool console_drop_id_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
151{
152 return WM_drag_get_local_ID(drag, 0) != nullptr;
153}
154
155static void console_drop_id_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
156{
157 ID *id = WM_drag_get_local_ID(drag, 0);
158
159 /* copy drag path to properties */
160 std::string text = RNA_path_full_ID_py(id);
161 RNA_string_set(drop->ptr, "text", text.c_str());
162}
163
164static bool console_drop_path_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
165{
166 return (drag->type == WM_DRAG_PATH);
167}
168
169static void console_drop_path_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
170{
171 char pathname[FILE_MAX + 2];
172 SNPRINTF(pathname, "\"%s\"", WM_drag_get_single_path(drag));
173 RNA_string_set(drop->ptr, "text", pathname);
174}
175
176static bool console_drop_string_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
177{
178 return (drag->type == WM_DRAG_STRING);
179}
180
181static void console_drop_string_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
182{
183 /* NOTE(@ideasman42): Only a single line is supported, multiple lines could be supported
184 * but this implies executing all lines except for the last. While we could consider that,
185 * there are some security implications for this, so just drop one line for now. */
186 std::string str = WM_drag_get_string_firstline(drag);
187 RNA_string_set(drop->ptr, "text", str.c_str());
188}
189
190/* this region dropbox definition */
191static void console_dropboxes()
192{
194
196 lb, "CONSOLE_OT_insert", console_drop_id_poll, console_drop_id_copy, nullptr, nullptr);
198 lb, "CONSOLE_OT_insert", console_drop_path_poll, console_drop_path_copy, nullptr, nullptr);
200 "CONSOLE_OT_insert",
203 nullptr,
204 nullptr);
205}
206
207/* ************* end drop *********** */
208
209static void console_main_region_draw(const bContext *C, ARegion *region)
210{
211 /* draw entirely, view changes should be handled here */
213 View2D *v2d = &region->v2d;
214
217 (bContext *)C, "CONSOLE_OT_banner", WM_OP_EXEC_DEFAULT, nullptr, nullptr);
218 }
219
220 /* clear and setup matrix */
222
223 /* Works best with no view2d matrix set. */
225
226 /* data... */
227
228 console_history_verify(C); /* make sure we have some command line */
229 console_textview_main(sc, region);
230
231 /* reset view matrix */
233
234 /* scrollers */
235 UI_view2d_scrollers_draw(v2d, nullptr);
236}
237
262
263static void console_keymap(wmKeyConfig *keyconf)
264{
265 WM_keymap_ensure(keyconf, "Console", SPACE_CONSOLE, RGN_TYPE_WINDOW);
266}
267
268/****************** header region ******************/
269
270/* add handlers, stuff you only do once or on area/region changes */
272{
273 ED_region_header_init(region);
274}
275
276static void console_header_region_draw(const bContext *C, ARegion *region)
277{
278 ED_region_header(C, region);
279}
280
282{
283 ScrArea *area = params->area;
284 ARegion *region = params->region;
285 const wmNotifier *wmn = params->notifier;
286
287 /* context changes */
288 switch (wmn->category) {
289 case NC_SPACE: {
290 if (wmn->data == ND_SPACE_CONSOLE) {
291 if (wmn->action == NA_EDITED) {
292 if ((wmn->reference && area) && (wmn->reference == area->spacedata.first)) {
293 /* we've modified the geometry (font size), re-calculate rect */
294 console_textview_update_rect(static_cast<SpaceConsole *>(wmn->reference), region);
295 ED_region_tag_redraw(region);
296 }
297 }
298 else {
299 /* generic redraw request */
300 ED_region_tag_redraw(region);
301 }
302 }
303 break;
304 }
305 }
306}
307
309{
310 SpaceConsole *sconsole = (SpaceConsole *)sl;
311
312 BLO_read_struct_list(reader, ConsoleLine, &sconsole->scrollback);
313 BLO_read_struct_list(reader, ConsoleLine, &sconsole->history);
314
315 /* Comma expressions, (e.g. expr1, expr2, expr3) evaluate each expression,
316 * from left to right. the right-most expression sets the result of the comma
317 * expression as a whole. */
318 LISTBASE_FOREACH_MUTABLE (ConsoleLine *, cl, &sconsole->history) {
319 BLO_read_char_array(reader, size_t(cl->len) + 1, &cl->line);
320 if (cl->line) {
321 /* The allocated length is not written, so reset here. */
322 cl->len_alloc = cl->len + 1;
323 }
324 else {
325 BLI_remlink(&sconsole->history, cl);
326 MEM_freeN(cl);
327 }
328 }
329}
330
332{
333 SpaceConsole *con = (SpaceConsole *)sl;
334
335 LISTBASE_FOREACH (ConsoleLine *, cl, &con->history) {
336 /* 'len_alloc' is invalid on write, set from 'len' on read */
337 BLO_write_struct(writer, ConsoleLine, cl);
338 BLO_write_char_array(writer, size_t(cl->len) + 1, cl->line);
339 }
340 BLO_write_struct(writer, SpaceConsole, sl);
341}
342
344{
345 std::unique_ptr<SpaceType> st = std::make_unique<SpaceType>();
346 ARegionType *art;
347
348 st->spaceid = SPACE_CONSOLE;
349 STRNCPY(st->name, "Console");
350
351 st->create = console_create;
352 st->free = console_free;
353 st->init = console_init;
354 st->duplicate = console_duplicate;
355 st->operatortypes = console_operatortypes;
356 st->keymap = console_keymap;
357 st->dropboxes = console_dropboxes;
358 st->blend_read_data = console_blend_read_data;
359 st->blend_write = console_space_blend_write;
360
361 /* regions: main window */
362 art = MEM_callocN<ARegionType>("spacetype console region");
365
368 art->cursor = console_cursor;
369 art->event_cursor = true;
371
372 BLI_addhead(&st->regiontypes, art);
373
374 /* regions: header */
375 art = MEM_callocN<ARegionType>("spacetype console region");
377 art->prefsizey = HEADERY;
379
382
383 BLI_addhead(&st->regiontypes, art);
384
385 BKE_spacetype_register(std::move(st));
386}
SpaceConsole * CTX_wm_space_console(const bContext *C)
void BKE_spacetype_register(std::unique_ptr< SpaceType > st)
Definition screen.cc:276
ARegion * BKE_area_region_new()
Definition screen.cc:381
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
#define FILE_MAX
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
void BLO_read_char_array(BlendDataReader *reader, int64_t array_size, char **ptr_p)
Definition readfile.cc:5278
void BLO_write_char_array(BlendWriter *writer, int64_t num, const char *data_ptr)
#define HEADERY
@ RGN_TYPE_WINDOW
@ RGN_TYPE_HEADER
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_TOP
@ SPACE_CONSOLE
@ SPACE_EMPTY
@ USER_HEADER_BOTTOM
@ V2D_SCROLL_VERTICAL_HIDE
@ V2D_SCROLL_RIGHT
@ V2D_LOCKOFS_X
@ V2D_ALIGN_NO_NEG_X
@ V2D_ALIGN_NO_NEG_Y
@ V2D_LIMITZOOM
@ V2D_LOCKZOOM_X
@ V2D_KEEPASPECT
@ V2D_LOCKZOOM_Y
@ V2D_KEEPTOT_BOUNDS
@ ED_KEYMAP_UI
Definition ED_screen.hh:740
@ ED_KEYMAP_HEADER
Definition ED_screen.hh:746
@ ED_KEYMAP_VIEW2D
Definition ED_screen.hh:743
void ED_region_header(const bContext *C, ARegion *region)
Definition area.cc:3754
void ED_region_header_init(ARegion *region)
Definition area.cc:3769
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:639
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ TH_BACK
void UI_ThemeClearColor(int colorid)
char char UI_view2d_mouse_in_scrollers(const ARegion *region, const View2D *v2d, const int xy[2]) ATTR_NONNULL(1
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
Definition view2d.cc:1503
void UI_view2d_view_restore(const bContext *C)
Definition view2d.cc:1162
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
Definition view2d.cc:221
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1095
@ V2D_COMMONVIEW_CUSTOM
Definition UI_view2d.hh:31
#define NA_EDITED
Definition WM_types.hh:581
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:245
@ WM_DRAG_PATH
Definition WM_types.hh:1205
@ WM_DRAG_STRING
Definition WM_types.hh:1214
#define ND_SPACE_CONSOLE
Definition WM_types.hh:516
#define NC_SPACE
Definition WM_types.hh:389
#define U
void console_textview_main(SpaceConsole *sc, const ARegion *region)
void CONSOLE_OT_select_all(wmOperatorType *ot)
void CONSOLE_OT_copy(wmOperatorType *ot)
void CONSOLE_OT_clear(wmOperatorType *ot)
void console_textview_update_rect(SpaceConsole *sc, ARegion *region)
void CONSOLE_OT_select_word(wmOperatorType *ot)
void CONSOLE_OT_delete(wmOperatorType *ot)
void CONSOLE_OT_indent(wmOperatorType *ot)
void CONSOLE_OT_select_set(wmOperatorType *ot)
void CONSOLE_OT_indent_or_autocomplete(wmOperatorType *ot)
void CONSOLE_OT_move(wmOperatorType *ot)
void console_history_free(SpaceConsole *sc, ConsoleLine *cl)
void console_scrollback_free(SpaceConsole *sc, ConsoleLine *cl)
void CONSOLE_OT_clear_line(wmOperatorType *ot)
void CONSOLE_OT_scrollback_append(wmOperatorType *ot)
void CONSOLE_OT_insert(wmOperatorType *ot)
void CONSOLE_OT_history_cycle(wmOperatorType *ot)
void CONSOLE_OT_unindent(wmOperatorType *ot)
void CONSOLE_OT_history_append(wmOperatorType *ot)
void CONSOLE_OT_paste(wmOperatorType *ot)
ConsoleLine * console_history_verify(const bContext *C)
#define str(s)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
std::string RNA_path_full_ID_py(ID *id)
Definition rna_path.cc:1232
static void console_space_blend_write(BlendWriter *writer, SpaceLink *sl)
static void console_operatortypes()
static void console_cursor(wmWindow *win, ScrArea *, ARegion *region)
static bool console_drop_id_poll(bContext *, wmDrag *drag, const wmEvent *)
static bool console_drop_path_poll(bContext *, wmDrag *drag, const wmEvent *)
static void console_dropboxes()
static void console_free(SpaceLink *sl)
static void console_drop_path_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static void console_header_region_draw(const bContext *C, ARegion *region)
static void console_init(wmWindowManager *, ScrArea *)
static void console_main_region_draw(const bContext *C, ARegion *region)
static SpaceLink * console_create(const ScrArea *, const Scene *)
static void console_main_region_listener(const wmRegionListenerParams *params)
static bool console_drop_string_poll(bContext *, wmDrag *drag, const wmEvent *)
void ED_spacetype_console()
static void console_keymap(wmKeyConfig *keyconf)
static void console_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static SpaceLink * console_duplicate(SpaceLink *sl)
static void console_drop_string_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static void console_header_region_init(wmWindowManager *, ARegion *region)
static void console_drop_id_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static void console_main_region_init(wmWindowManager *wm, ARegion *region)
void(* cursor)(wmWindow *win, ScrArea *area, ARegion *region)
void(* listener)(const wmRegionListenerParams *params)
void(* draw)(const bContext *C, ARegion *region)
short event_cursor
void(* init)(wmWindowManager *wm, ARegion *region)
ARegionRuntimeHandle * runtime
Definition DNA_ID.h:404
void * first
ListBase spacedata
ListBase regionbase
ListBase scrollback
float minzoom
short keeptot
short keepzoom
short keepofs
float maxzoom
float ymax
float ymin
eWM_DragDataType type
Definition WM_types.hh:1327
PointerRNA * ptr
Definition WM_types.hh:1415
unsigned int data
Definition WM_types.hh:355
unsigned int action
Definition WM_types.hh:355
unsigned int category
Definition WM_types.hh:355
void * reference
Definition WM_types.hh:357
struct wmKeyConfig * defaultconf
struct wmEvent * eventstate
void WM_cursor_set(wmWindow *win, int curs)
@ WM_CURSOR_DEFAULT
Definition wm_cursors.hh:15
@ WM_CURSOR_TEXT_EDIT
Definition wm_cursors.hh:16
wmDropBox * WM_dropbox_add(ListBase *lb, const char *idname, bool(*poll)(bContext *C, wmDrag *drag, const wmEvent *event), void(*copy)(bContext *C, wmDrag *drag, wmDropBox *drop), void(*cancel)(Main *bmain, wmDrag *drag, wmDropBox *drop), WMDropboxTooltipFunc tooltip)
const char * WM_drag_get_single_path(const wmDrag *drag)
ListBase * WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
std::string WM_drag_get_string_firstline(const wmDrag *drag)
ID * WM_drag_get_local_ID(const wmDrag *drag, short idcode)
wmEventHandler_Dropbox * WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
wmEventHandler_Keymap * WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
wmOperatorStatus WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
wmEventHandler_Keymap * WM_event_add_keymap_handler_v2d_mask(ListBase *handlers, wmKeyMap *keymap)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:893
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))