554 lines
14 KiB
C
554 lines
14 KiB
C
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* Contributor(s): Blender Foundation
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file blender/editors/space_text/text_python.c
|
|
* \ingroup sptext
|
|
*/
|
|
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_space_types.h"
|
|
#include "DNA_text_types.h"
|
|
|
|
#include "BKE_suggestions.h"
|
|
#include "BKE_text.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
#include "text_intern.h"
|
|
|
|
int text_do_suggest_select(SpaceText *st, ARegion *ar)
|
|
{
|
|
SuggItem *item, *first, *last /* , *sel */ /* UNUSED */;
|
|
TextLine *tmp;
|
|
int l, x, y, w, h, i;
|
|
int tgti, *top;
|
|
int mval[2] = {0, 0};
|
|
|
|
if (!st || !st->text) return 0;
|
|
if (!texttool_text_is_active(st->text)) return 0;
|
|
|
|
first = texttool_suggest_first();
|
|
last = texttool_suggest_last();
|
|
/* sel = texttool_suggest_selected(); */ /* UNUSED */
|
|
top = texttool_suggest_top();
|
|
|
|
if (!last || !first)
|
|
return 0;
|
|
|
|
/* Count the visible lines to the cursor */
|
|
for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ;
|
|
if (l < 0) return 0;
|
|
|
|
text_update_character_width(st);
|
|
|
|
if (st->showlinenrs) {
|
|
x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4;
|
|
}
|
|
else {
|
|
x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4;
|
|
}
|
|
y = ar->winy - st->lheight * l - 2;
|
|
|
|
w = SUGG_LIST_WIDTH * st->cwidth + 20;
|
|
h = SUGG_LIST_SIZE * st->lheight + 8;
|
|
|
|
// XXX getmouseco_areawin(mval);
|
|
|
|
if (mval[0] < x || x + w < mval[0] || mval[1] < y - h || y < mval[1])
|
|
return 0;
|
|
|
|
/* Work out which of the items is at the top of the visible list */
|
|
for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ;
|
|
|
|
/* Work out the target item index in the visible list */
|
|
tgti = (y - mval[1] - 4) / st->lheight;
|
|
if (tgti < 0 || tgti > SUGG_LIST_SIZE)
|
|
return 1;
|
|
|
|
for (i = tgti; i > 0 && item->next; i--, item = item->next) ;
|
|
if (item)
|
|
texttool_suggest_select(item);
|
|
return 1;
|
|
}
|
|
|
|
void text_pop_suggest_list(void)
|
|
{
|
|
SuggItem *item, *sel;
|
|
int *top, i;
|
|
|
|
item = texttool_suggest_first();
|
|
sel = texttool_suggest_selected();
|
|
top = texttool_suggest_top();
|
|
|
|
i = 0;
|
|
while (item && item != sel) {
|
|
item = item->next;
|
|
i++;
|
|
}
|
|
if (i > *top + SUGG_LIST_SIZE - 1)
|
|
*top = i - SUGG_LIST_SIZE + 1;
|
|
else if (i < *top)
|
|
*top = i;
|
|
}
|
|
|
|
static void get_suggest_prefix(Text *text, int offset)
|
|
{
|
|
int i, len;
|
|
char *line, tmp[256];
|
|
|
|
if (!text) return;
|
|
if (!texttool_text_is_active(text)) return;
|
|
|
|
line = text->curl->line;
|
|
for (i = text->curc - 1 + offset; i >= 0; i--)
|
|
if (!text_check_identifier(line[i]))
|
|
break;
|
|
i++;
|
|
len = text->curc - i + offset;
|
|
if (len > 255) {
|
|
printf("Suggestion prefix too long\n");
|
|
len = 255;
|
|
}
|
|
BLI_strncpy(tmp, line + i, len);
|
|
tmp[len] = '\0';
|
|
texttool_suggest_prefix(tmp);
|
|
}
|
|
|
|
static void confirm_suggestion(Text *text, int skipleft)
|
|
{
|
|
SuggItem *sel;
|
|
int i, over = 0;
|
|
char *line;
|
|
|
|
if (!text) return;
|
|
if (!texttool_text_is_active(text)) return;
|
|
|
|
sel = texttool_suggest_selected();
|
|
if (!sel) return;
|
|
|
|
line = text->curl->line;
|
|
i = text->curc - skipleft - 1;
|
|
while (i >= 0) {
|
|
if (!text_check_identifier(line[i]))
|
|
break;
|
|
over++;
|
|
i--;
|
|
}
|
|
|
|
for (i = 0; i < skipleft; i++)
|
|
txt_move_left(text, 0);
|
|
for (i = 0; i < over; i++)
|
|
txt_move_left(text, 1);
|
|
|
|
txt_insert_buf(text, sel->name);
|
|
|
|
for (i = 0; i < skipleft; i++)
|
|
txt_move_right(text, 0);
|
|
|
|
texttool_text_clear();
|
|
}
|
|
|
|
// XXX
|
|
#define L_MOUSE 0
|
|
#define M_MOUSE 0
|
|
#define R_MOUSE 0
|
|
#define LR_SHIFTKEY 0
|
|
#define LR_ALTKEY 0
|
|
#define LR_CTRLKEY 0
|
|
#define LR_OSKEY 0
|
|
|
|
// XXX
|
|
static int doc_scroll = 0;
|
|
|
|
static short UNUSED_FUNCTION(do_texttools) (SpaceText * st, char ascii, unsigned short evnt, short val)
|
|
{
|
|
ARegion *ar = NULL; // XXX
|
|
int qual = 0; // XXX
|
|
int draw = 0, tools = 0, swallow = 0, scroll = 1;
|
|
if (!texttool_text_is_active(st->text)) return 0;
|
|
if (!st->text || st->text->id.lib) return 0;
|
|
|
|
if (st->doplugins && texttool_text_is_active(st->text)) {
|
|
if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
|
|
if (texttool_docs_get()) tools |= TOOL_DOCUMENT;
|
|
}
|
|
|
|
if (ascii) {
|
|
if (tools & TOOL_SUGG_LIST) {
|
|
if ((ascii != '_' && ascii != '*' && ispunct(ascii)) || text_check_whitespace(ascii)) {
|
|
confirm_suggestion(st->text, 0);
|
|
text_update_line_edited(st->text->curl);
|
|
}
|
|
else if ((st->overwrite && txt_replace_char(st->text, ascii)) || txt_add_char(st->text, ascii)) {
|
|
get_suggest_prefix(st->text, 0);
|
|
text_pop_suggest_list();
|
|
swallow = 1;
|
|
draw = 1;
|
|
}
|
|
}
|
|
if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
|
|
|
|
}
|
|
else if (val == 1 && evnt) {
|
|
switch (evnt) {
|
|
case LEFTMOUSE:
|
|
if (text_do_suggest_select(st, ar))
|
|
swallow = 1;
|
|
else {
|
|
if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
|
|
if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
|
|
}
|
|
draw = 1;
|
|
break;
|
|
case MIDDLEMOUSE:
|
|
if (text_do_suggest_select(st, ar)) {
|
|
confirm_suggestion(st->text, 0);
|
|
text_update_line_edited(st->text->curl);
|
|
swallow = 1;
|
|
}
|
|
else {
|
|
if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
|
|
if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
|
|
}
|
|
draw = 1;
|
|
break;
|
|
case ESCKEY:
|
|
draw = swallow = 1;
|
|
if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
|
|
else if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
|
|
else draw = swallow = 0;
|
|
break;
|
|
case RETKEY:
|
|
if (tools & TOOL_SUGG_LIST) {
|
|
confirm_suggestion(st->text, 0);
|
|
text_update_line_edited(st->text->curl);
|
|
swallow = 1;
|
|
draw = 1;
|
|
}
|
|
if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
|
|
break;
|
|
case LEFTARROWKEY:
|
|
case BACKSPACEKEY:
|
|
if (tools & TOOL_SUGG_LIST) {
|
|
if (qual)
|
|
texttool_suggest_clear();
|
|
else {
|
|
/* Work out which char we are about to delete/pass */
|
|
if (st->text->curl && st->text->curc > 0) {
|
|
char ch = st->text->curl->line[st->text->curc - 1];
|
|
if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
|
|
get_suggest_prefix(st->text, -1);
|
|
text_pop_suggest_list();
|
|
}
|
|
else
|
|
texttool_suggest_clear();
|
|
}
|
|
else
|
|
texttool_suggest_clear();
|
|
}
|
|
}
|
|
if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
|
|
break;
|
|
case RIGHTARROWKEY:
|
|
if (tools & TOOL_SUGG_LIST) {
|
|
if (qual)
|
|
texttool_suggest_clear();
|
|
else {
|
|
/* Work out which char we are about to pass */
|
|
if (st->text->curl && st->text->curc < st->text->curl->len) {
|
|
char ch = st->text->curl->line[st->text->curc + 1];
|
|
if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
|
|
get_suggest_prefix(st->text, 1);
|
|
text_pop_suggest_list();
|
|
}
|
|
else
|
|
texttool_suggest_clear();
|
|
}
|
|
else
|
|
texttool_suggest_clear();
|
|
}
|
|
}
|
|
if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
|
|
break;
|
|
case PAGEDOWNKEY:
|
|
scroll = SUGG_LIST_SIZE - 1;
|
|
case WHEELDOWNMOUSE:
|
|
case DOWNARROWKEY:
|
|
if (tools & TOOL_DOCUMENT) {
|
|
doc_scroll++;
|
|
swallow = 1;
|
|
draw = 1;
|
|
break;
|
|
}
|
|
else if (tools & TOOL_SUGG_LIST) {
|
|
SuggItem *sel = texttool_suggest_selected();
|
|
if (!sel) {
|
|
texttool_suggest_select(texttool_suggest_first());
|
|
}
|
|
else {
|
|
while (sel && sel != texttool_suggest_last() && sel->next && scroll--) {
|
|
texttool_suggest_select(sel->next);
|
|
sel = sel->next;
|
|
}
|
|
}
|
|
text_pop_suggest_list();
|
|
swallow = 1;
|
|
draw = 1;
|
|
break;
|
|
}
|
|
case PAGEUPKEY:
|
|
scroll = SUGG_LIST_SIZE - 1;
|
|
case WHEELUPMOUSE:
|
|
case UPARROWKEY:
|
|
if (tools & TOOL_DOCUMENT) {
|
|
if (doc_scroll > 0) doc_scroll--;
|
|
swallow = 1;
|
|
draw = 1;
|
|
break;
|
|
}
|
|
else if (tools & TOOL_SUGG_LIST) {
|
|
SuggItem *sel = texttool_suggest_selected();
|
|
while (sel && sel != texttool_suggest_first() && sel->prev && scroll--) {
|
|
texttool_suggest_select(sel->prev);
|
|
sel = sel->prev;
|
|
}
|
|
text_pop_suggest_list();
|
|
swallow = 1;
|
|
draw = 1;
|
|
break;
|
|
}
|
|
case RIGHTSHIFTKEY:
|
|
case LEFTSHIFTKEY:
|
|
break;
|
|
default:
|
|
if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw = 1;
|
|
if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
|
|
}
|
|
}
|
|
|
|
if (draw) {
|
|
// XXX redraw_alltext();
|
|
}
|
|
|
|
return swallow;
|
|
}
|
|
|
|
#if 0
|
|
#ifdef WITH_PYTHON
|
|
/* Run text plugin scripts if enabled */
|
|
if (st->doplugins && event && val)
|
|
{
|
|
if (BPY_menu_do_shortcut(PYMENU_TEXTPLUGIN, event, qual)) {
|
|
do_draw = 1;
|
|
}
|
|
}
|
|
#endif
|
|
if (do_draw)
|
|
; // XXX redraw_alltext();
|
|
#endif
|
|
|
|
static short UNUSED_FUNCTION(do_textmarkers) (SpaceText * st, char ascii, unsigned short evnt, short val)
|
|
{
|
|
Text *text;
|
|
TextMarker *marker, *mrk, *nxt;
|
|
int c, s, draw = 0, swallow = 0;
|
|
int qual = 0; // XXX
|
|
|
|
text = st->text;
|
|
if (!text || text->id.lib || text->curl != text->sell) return 0;
|
|
|
|
marker = txt_find_marker(text, text->sell, text->selc, 0, 0);
|
|
if (marker && (marker->start > text->curc || marker->end < text->curc))
|
|
marker = NULL;
|
|
|
|
if (!marker) {
|
|
/* Find the next temporary marker */
|
|
if (evnt == TABKEY) {
|
|
int lineno = txt_get_span(text->lines.first, text->curl);
|
|
mrk = text->markers.first;
|
|
while (mrk) {
|
|
if (!marker && (mrk->flags & TMARK_TEMP)) marker = mrk;
|
|
if ((mrk->flags & TMARK_TEMP) && (mrk->lineno > lineno || (mrk->lineno == lineno && mrk->end > text->curc))) {
|
|
marker = mrk;
|
|
break;
|
|
}
|
|
mrk = mrk->next;
|
|
}
|
|
if (marker) {
|
|
txt_move_to(text, marker->lineno, marker->start, 0);
|
|
txt_move_to(text, marker->lineno, marker->end, 1);
|
|
// XXX text_update_cursor_moved(C);
|
|
// XXX WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
|
|
evnt = ascii = val = 0;
|
|
draw = 1;
|
|
swallow = 1;
|
|
}
|
|
}
|
|
else if (evnt == ESCKEY) {
|
|
if (txt_clear_markers(text, 0, TMARK_TEMP)) swallow = 1;
|
|
else if (txt_clear_markers(text, 0, 0)) swallow = 1;
|
|
else return 0;
|
|
evnt = ascii = val = 0;
|
|
draw = 1;
|
|
}
|
|
if (!swallow) return 0;
|
|
}
|
|
|
|
if (ascii) {
|
|
if (marker->flags & TMARK_EDITALL) {
|
|
c = text->curc - marker->start;
|
|
s = text->selc - marker->start;
|
|
if (s < 0 || s > marker->end - marker->start) return 0;
|
|
|
|
mrk = txt_next_marker(text, marker);
|
|
while (mrk) {
|
|
nxt = txt_next_marker(text, mrk); /* mrk may become invalid */
|
|
txt_move_to(text, mrk->lineno, mrk->start + c, 0);
|
|
if (s != c) txt_move_to(text, mrk->lineno, mrk->start + s, 1);
|
|
if (st->overwrite) {
|
|
if (txt_replace_char(text, ascii))
|
|
text_update_line_edited(st->text->curl);
|
|
}
|
|
else {
|
|
if (txt_add_char(text, ascii)) {
|
|
text_update_line_edited(st->text->curl);
|
|
}
|
|
}
|
|
|
|
if (mrk == marker || mrk == nxt) break;
|
|
mrk = nxt;
|
|
}
|
|
swallow = 1;
|
|
draw = 1;
|
|
}
|
|
}
|
|
else if (val) {
|
|
switch (evnt) {
|
|
case BACKSPACEKEY:
|
|
if (marker->flags & TMARK_EDITALL) {
|
|
c = text->curc - marker->start;
|
|
s = text->selc - marker->start;
|
|
if (s < 0 || s > marker->end - marker->start) return 0;
|
|
|
|
mrk = txt_next_marker(text, marker);
|
|
while (mrk) {
|
|
nxt = txt_next_marker(text, mrk); /* mrk may become invalid */
|
|
txt_move_to(text, mrk->lineno, mrk->start + c, 0);
|
|
if (s != c) txt_move_to(text, mrk->lineno, mrk->start + s, 1);
|
|
txt_backspace_char(text);
|
|
text_update_line_edited(st->text->curl);
|
|
if (mrk == marker || mrk == nxt) break;
|
|
mrk = nxt;
|
|
}
|
|
swallow = 1;
|
|
draw = 1;
|
|
}
|
|
break;
|
|
case DELKEY:
|
|
if (marker->flags & TMARK_EDITALL) {
|
|
c = text->curc - marker->start;
|
|
s = text->selc - marker->start;
|
|
if (s < 0 || s > marker->end - marker->start) return 0;
|
|
|
|
mrk = txt_next_marker(text, marker);
|
|
while (mrk) {
|
|
nxt = txt_next_marker(text, mrk); /* mrk may become invalid */
|
|
txt_move_to(text, mrk->lineno, mrk->start + c, 0);
|
|
if (s != c) txt_move_to(text, mrk->lineno, mrk->start + s, 1);
|
|
txt_delete_char(text);
|
|
text_update_line_edited(st->text->curl);
|
|
if (mrk == marker || mrk == nxt) break;
|
|
mrk = nxt;
|
|
}
|
|
swallow = 1;
|
|
draw = 1;
|
|
}
|
|
break;
|
|
case TABKEY:
|
|
if (qual & LR_SHIFTKEY) {
|
|
nxt = marker->prev;
|
|
if (!nxt) nxt = text->markers.last;
|
|
}
|
|
else {
|
|
nxt = marker->next;
|
|
if (!nxt) nxt = text->markers.first;
|
|
}
|
|
if (marker->flags & TMARK_TEMP) {
|
|
if (nxt == marker) nxt = NULL;
|
|
BLI_freelinkN(&text->markers, marker);
|
|
}
|
|
mrk = nxt;
|
|
if (mrk) {
|
|
txt_move_to(text, mrk->lineno, mrk->start, 0);
|
|
txt_move_to(text, mrk->lineno, mrk->end, 1);
|
|
// XXX text_update_cursor_moved(C);
|
|
// XXX WM_event_add_notifier(C, NC_TEXT|ND_CURSOR, text);
|
|
}
|
|
swallow = 1;
|
|
draw = 1;
|
|
break;
|
|
|
|
/* Events that should clear markers */
|
|
case UKEY: if (!(qual & LR_ALTKEY)) break;
|
|
case ZKEY: if (evnt == ZKEY && !(qual & LR_CTRLKEY)) break;
|
|
case RETKEY:
|
|
case ESCKEY:
|
|
if (marker->flags & (TMARK_EDITALL | TMARK_TEMP))
|
|
txt_clear_markers(text, marker->group, 0);
|
|
else
|
|
BLI_freelinkN(&text->markers, marker);
|
|
swallow = 1;
|
|
draw = 1;
|
|
break;
|
|
case RIGHTMOUSE: /* Marker context menu? */
|
|
case LEFTMOUSE:
|
|
break;
|
|
case FKEY: /* Allow find */
|
|
if (qual & LR_SHIFTKEY) swallow = 1;
|
|
break;
|
|
|
|
default:
|
|
if (qual != 0 && qual != LR_SHIFTKEY)
|
|
swallow = 1; /* Swallow all other shortcut events */
|
|
}
|
|
}
|
|
|
|
if (draw) {
|
|
// XXX redraw_alltext();
|
|
}
|
|
|
|
return swallow;
|
|
}
|
|
|