Page MenuHome

drawstdout.c

File Metadata

Author
Jacques Beaurain (jbinto)
Created
Nov 13 2013, 1:02 PM

drawstdout.c

/**
* $Id: drawtext.c,v 1.58 2006/03/05 19:56:31 themyers Exp $
*
* ***** BEGIN GPL/BL DUAL 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. The Blender
* Foundation also sells licenses for use in proprietary software under
* the Blender License. See http://www.blender.org/BL/ for information
* about this.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* This is a new part of Blender.
*
* Contributor(s): Jacques Beaurain
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef _WIN32
#include <unistd.h>
#else
#include "BLI_winstuff.h"
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#endif
#include <pthread.h>
#include "MEM_guardedalloc.h"
#include "PIL_time.h"
#include "BMF_Api.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "DNA_text_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BKE_utildefines.h"
#include "BKE_stdout.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BIF_gl.h"
#include "BIF_keyval.h"
#include "BIF_interface.h"
#include "BIF_drawstdout.h"
#include "BIF_editfont.h"
#include "BIF_spacetypes.h"
#include "BIF_usiblender.h"
#include "BIF_screen.h"
#include "BIF_toolbox.h"
#include "BIF_space.h"
#include "BIF_mywindow.h"
#include "BIF_resources.h"
#include "BSE_filesel.h"
#include "BPY_extern.h"
#include "mydevice.h"
#include "blendef.h"
#define TEXTXLOC 38
/* forward declarations */
void drawstdoutspace(ScrArea *sa, void *spacedata);
void winqreadstdoutspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
void txt_copy_selectbuffer (Text *text);
void txt_copy_clipboard(Text *text); /* blank on non Win32 */
static void *last_txt_find_string= NULL;
#define INITIAL_BUFF 256
static int stdwin_on = 0;
static struct Text *stdout_text = NULL;
static pthread_mutex_t _std_lock_out = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _std_lock_err = PTHREAD_MUTEX_INITIALIZER;
static pthread_t stdout_thread, stderr_thread;
#ifdef WIN32
static HANDLE houtread, houtwrite, herrread, herrwrite;
static int cfdout, cfderr;
static FILE *fout = NULL, *ferr = NULL;
#else
static int outpipe[2], errpipe[2];
static FILE *fiout = NULL, *fierr = NULL;
#endif
static char *poutbuf = NULL, *perrbuf = NULL;
static int outsize, errsize;
static int outpos, errpos;
static void ensurebuffsize(int req_wrksize, int *wrksize, char **ppbuf)
{
int new_size;
char* new_buff;
if (*wrksize < req_wrksize)
{
new_size = (((req_wrksize >> 8) + 1) << 8);
new_buff = malloc(new_size);
memcpy(new_buff, *ppbuf, *wrksize);
free(*ppbuf);
*wrksize = new_size;
*ppbuf = new_buff;
}
}
static void std_lock_thread_out()
{
pthread_mutex_lock(&_std_lock_out);
}
void std_unlock_thread_out()
{
pthread_mutex_unlock(&_std_lock_out);
}
static void std_lock_thread_err()
{
pthread_mutex_lock(&_std_lock_err);
}
void std_unlock_thread_err()
{
pthread_mutex_unlock(&_std_lock_err);
}
static void* stdout_readthread(void *pinfo)
{
#ifdef WIN32
DWORD dw;
#else
int iget;
#endif
char ch;
for( ;; )
{
#ifdef WIN32
if(!ReadFile((HANDLE)pinfo, &ch, 1, &dw, NULL) || dw == 0)
break;
#else
pthread_testcancel();
iget = getc((FILE*)pinfo);
pthread_testcancel();
if (iget == EOF)
break;
ch = (char) iget;
#endif
std_lock_thread_out();
ensurebuffsize(outpos+1, &outsize, &poutbuf);
poutbuf[outpos] = ch;
outpos++;
std_unlock_thread_out();
/* Redraw on newline characters */
if (G.curscreen && !G.background && (ch == 0x0A || ch == 0x0D))
allqueue(REDRAWSTDOUT, 0);
}
return 0;
}
static void* stderr_readthread(void *pinfo)
{
#ifdef WIN32
DWORD dw;
#else
int iget;
#endif
char ch;
for( ;; )
{
#ifdef WIN32
if(!ReadFile((HANDLE)pinfo, &ch, 1, &dw, NULL) || dw == 0)
break;
#else
pthread_testcancel();
iget = getc((FILE*)pinfo);
pthread_testcancel();
if (iget == EOF)
break;
ch = (char) iget;
#endif
std_lock_thread_err();
ensurebuffsize(errpos+1, &errsize, &perrbuf);
perrbuf[errpos] = ch;
errpos++;
std_unlock_thread_err();
/* Redraw on newline characters */
if (G.curscreen && !G.background && (ch == 0x0A || ch == 0x0D))
allqueue(REDRAWSTDOUT, 0);
}
return 0;
}
int stdout_ison()
{
return stdwin_on;
}
void redraw_stdout_now()
{
if (stdout_ison())
{
ScrArea *tempsa, *sa;
if( !during_script( ) && !G.background ) {
tempsa = curarea;
sa = G.curscreen->areabase.first;
while( sa ) {
if( sa->spacetype == SPACE_STDOUT ) {
scrarea_do_windraw( sa );
if( sa->headwin ) scrarea_do_headdraw( sa );
}
sa = sa->next;
}
if( curarea != tempsa )
areawinset( tempsa->win );
if( curarea ) { /* is null if Blender is in bg mode */
if( curarea->headwin )
scrarea_do_headdraw( curarea );
screen_swapbuffers( );
}
}
}
}
void std_clear_text()
{
if (stdout_text)
free_text(stdout_text);
stdout_text = add_empty_text();
}
struct Text *std_text()
{
if (!stdout_text)
stdout_text = add_empty_text();
return stdout_text;
}
void stdout_gettext(SpaceStdOut *st)
{
int i;
int added = 0;
if (stdwin_on)
{
int oldstate = txt_get_undostate( );
txt_set_undostate( 1 );
fflush(stdout);
std_lock_thread_out();
for (i=0; i<outpos; i++)
{
added = 1;
txt_move_eof(std_text(), 0);
txt_add_char(std_text(), poutbuf[i]);
}
outpos=0;
std_unlock_thread_out();
fflush(stderr);
std_lock_thread_err();
for (i=0; i<errpos; i++)
{
added = 1;
txt_move_eof(std_text(), 0);
/* Indicate error lines */
if (((TextLine*)std_text()->lines.last)->len==0)
{
txt_add_char(std_text(), 'e');
txt_add_char(std_text(), 'r');
txt_add_char(std_text(), 'r');
txt_add_char(std_text(), 'o');
txt_add_char(std_text(), 'r');
txt_add_char(std_text(), ':');
txt_add_char(std_text(), ' ');
}
txt_add_char(std_text(), perrbuf[i]);
}
if (added)
pop_space_stdout(st);
errpos=0;
std_unlock_thread_err();
txt_set_undostate( oldstate );
}
}
void init_stdthreads(int stdwin)
{
#ifdef WIN32
SECURITY_ATTRIBUTES sa;
#endif
stdwin_on = stdwin;
if (stdwin_on)
{
outpos = 0;
outsize = INITIAL_BUFF;
poutbuf = malloc(INITIAL_BUFF);
errpos = 0;
errsize = INITIAL_BUFF;
perrbuf = malloc(INITIAL_BUFF);
#ifdef WIN32
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
CreatePipe(&houtread,&houtwrite,&sa,0);
SetStdHandle(STD_OUTPUT_HANDLE,houtwrite);
CreatePipe(&herrread,&herrwrite,&sa,0);
SetStdHandle(STD_ERROR_HANDLE,herrwrite);
cfdout = _open_osfhandle((long)houtwrite, _O_TEXT);
cfderr = _open_osfhandle((long)herrwrite, _O_TEXT);
fout = _fdopen(cfdout, "w");
*stdout = *fout;
ferr = _fdopen(cfderr, "w");
*stderr = *ferr;
/* turn off buffering */
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
pthread_create(&stdout_thread, NULL, stdout_readthread, (void*) houtread);
pthread_create(&stderr_thread, NULL, stderr_readthread, (void*) herrread);
FreeConsole();
#else
pipe(outpipe);
pipe(errpipe);
/* turn off buffering */
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
dup2(outpipe[1], fileno(stdout));
dup2(errpipe[1], fileno(stderr));
fiout = fdopen(outpipe[0], "r");
fierr = fdopen(errpipe[0], "r");
pthread_create(&stdout_thread, NULL, stdout_readthread, (void*) fiout);
pthread_create(&stderr_thread, NULL, stderr_readthread, (void*) fierr);
#endif
}
}
void shutdown_stdthreads()
{
if (stdwin_on)
{
#ifdef WIN32
/* On Windows the ReadFile call is non-blocking in this case.
Closing the handles will allow the threads to finish */
fclose(fout);
fclose(ferr);
CloseHandle(houtread);
CloseHandle(herrread);
pthread_join(stdout_thread,0);
pthread_join(stderr_thread,0);
#else
/* On POSIX systems the read call is blocking (getch uses read internally).
We have to cancel the threads here first otherwise we never get out of here. */
pthread_cancel(stdout_thread);
pthread_cancel(stderr_thread);
close(outpipe[1]);
close(errpipe[1]);
/* Don't fclose the handles, it hangs on Macs for some reason */
/* We are exiting anyway so dangling handles will not matter. */
#endif
free(poutbuf);
free(perrbuf);
}
}
static BMF_Font *spacestdout_get_font(SpaceStdOut *st) {
static BMF_Font *scr12= NULL;
static BMF_Font *scr15= NULL;
switch (st->font_id) {
default:
case 0:
if (!scr12)
scr12= BMF_GetFont(BMF_kScreen12);
return scr12;
case 1:
if (!scr15)
scr15= BMF_GetFont(BMF_kScreen15);
return scr15;
}
}
static int spacestdout_get_fontwidth(SpaceStdOut *st) {
return BMF_GetCharacterWidth(spacestdout_get_font(st), ' ');
}
static char *temp_char_buf= NULL;
static int *temp_char_accum= NULL;
static int temp_char_len= 0;
static int temp_char_pos= 0;
static void temp_char_write(char c, int accum) {
if (temp_char_len==0 || temp_char_pos>=temp_char_len) {
char *nbuf; int *naccum;
int olen= temp_char_len;
if (olen) temp_char_len*= 2;
else temp_char_len= 256;
nbuf= MEM_mallocN(sizeof(*temp_char_buf)*temp_char_len, "temp_char_buf");
naccum= MEM_mallocN(sizeof(*temp_char_accum)*temp_char_len, "temp_char_accum");
if (olen) {
memcpy(nbuf, temp_char_buf, olen);
memcpy(naccum, temp_char_accum, olen);
MEM_freeN(temp_char_buf);
MEM_freeN(temp_char_accum);
}
temp_char_buf= nbuf;
temp_char_accum= naccum;
}
temp_char_buf[temp_char_pos]= c;
temp_char_accum[temp_char_pos]= accum;
if (c==0) temp_char_pos= 0;
else temp_char_pos++;
}
void free_std_data(void)
{
if (last_txt_find_string) MEM_freeN(last_txt_find_string);
if (temp_char_buf) MEM_freeN(temp_char_buf);
if (temp_char_accum) MEM_freeN(temp_char_accum);
}
static int render_string (char *in) {
int r = 0;
while(*in) {
temp_char_write(*in, r);
r++;
in++;
}
r= temp_char_pos;
temp_char_write(0, 0);
return r;
}
static int stdout_draw(SpaceStdOut *st, char *str, int cshift, int maxwidth, int draw, int x, int y, char *format) {
int r=0, w= 0;
char *in;
int *acc;
w= render_string(str);
if(w<cshift ) return 0; /* String is shorter than shift */
in= temp_char_buf+cshift;
acc= temp_char_accum+cshift;
w= w-cshift;
if (draw) {
glRasterPos2i(x, y);
BMF_DrawString(spacestdout_get_font(st), in);
} else {
while (w-- && *acc++ < maxwidth) {
r+= spacestdout_get_fontwidth(st);
}
}
if (cshift && r==0) return 0;
else
return r+TXT_OFFSET;
}
static void set_cursor_to_pos (SpaceStdOut *st, int x, int y, int sel)
{
Text *text;
TextLine **linep;
int *charp;
int w;
text= std_text();
if(sel) { linep= &text->sell; charp= &text->selc; }
else { linep= &text->curl; charp= &text->curc; }
y= (curarea->winy - y)/st->lheight;
y-= txt_get_span(text->lines.first, *linep) - st->top;
if (y>0) {
while (y-- != 0) if((*linep)->next) *linep= (*linep)->next;
} else if (y<0) {
while (y++ != 0) if((*linep)->prev) *linep= (*linep)->prev;
}
x-= TXT_OFFSET;
if (x<0) x= 0;
x = (x/spacestdout_get_fontwidth(st)) + st->left;
w= render_string((*linep)->line);
if(x<w) *charp= temp_char_accum[x];
else *charp= (*linep)->len;
if(!sel) txt_pop_sel(text);
}
static void draw_cursor(SpaceStdOut *st) {
int h, x, i;
Text *text= std_text();
TextLine *linef, *linel;
int charf, charl;
if (text->curl==text->sell && text->curc==text->selc) {
x= stdout_draw(st, text->curl->line, st->left, text->curc, 0, 0, 0, NULL);
if (x) {
h= txt_get_span(text->lines.first, text->curl) - st->top;
BIF_ThemeColor(TH_HILITE);
glRecti(x-1, curarea->winy-st->lheight*(h)-2, x+1, curarea->winy-st->lheight*(h+1)-2);
}
} else {
int span= txt_get_span(text->curl, text->sell);
if (span<0) {
linef= text->sell;
charf= text->selc;
linel= text->curl;
charl= text->curc;
} else if (span>0) {
linef= text->curl;
charf= text->curc;
linel= text->sell;
charl= text->selc;
} else {
linef= linel= text->curl;
if (text->curc<text->selc) {
charf= text->curc;
charl= text->selc;
} else {
charf= text->selc;
charl= text->curc;
}
}
/* Walk to the beginning of visible text */
h= txt_get_span(text->lines.first, linef) - st->top;
while (h++<-1 && linef!=linel) linef= linef->next;
x= stdout_draw(st, linef->line, st->left, charf, 0, 0, 0, NULL);
BIF_ThemeColor(TH_SHADE2);
if (!x) x= TXT_OFFSET - 14;
while (linef && linef != linel) {
h= txt_get_span(text->lines.first, linef) - st->top;
if (h>st->viewlines) break;
glRecti(x, curarea->winy-st->lheight*(h)-2, curarea->winx, curarea->winy-st->lheight*(h+1)-2);
glRecti(TXT_OFFSET-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET, curarea->winy-st->lheight*(h+2)-2);
x= TXT_OFFSET;
linef= linef->next;
}
h= txt_get_span(text->lines.first, linef) - st->top;
i= stdout_draw(st, linel->line, st->left, charl, 0, 0, 0, NULL);
if(i) glRecti(x, curarea->winy-st->lheight*(h)-2, i, curarea->winy-st->lheight*(h+1)-2);
}
BIF_ThemeColor(TH_TEXT);
}
static void calc_stdout_rcts(SpaceStdOut *st)
{
short barheight, barstart;
int lbarstart, lbarh, ltexth;
lbarstart= st->top;
lbarh= st->viewlines;
ltexth= txt_get_span(std_text()->lines.first, std_text()->lines.last)+1;
barheight= (lbarh*(curarea->winy-4))/ltexth;
if (barheight<20) barheight=20;
barstart= (lbarstart*(curarea->winy-4))/ltexth + 8;
st->txtbar.xmin= 5;
st->txtbar.xmax= 17;
st->txtbar.ymax= curarea->winy - barstart;
st->txtbar.ymin= st->txtbar.ymax - barheight;
CLAMP(st->txtbar.ymin, 2, curarea->winy-2);
CLAMP(st->txtbar.ymax, 2, curarea->winy-2);
st->pix_per_line= (float) ltexth/curarea->winy;
if (st->pix_per_line<.1) st->pix_per_line=.1f;
lbarstart= MIN2(txt_get_span(std_text()->lines.first, std_text()->curl),
txt_get_span(std_text()->lines.first, std_text()->sell));
lbarh= abs(txt_get_span(std_text()->lines.first, std_text()->curl)-txt_get_span(std_text()->lines.first, std_text()->sell));
barheight= (lbarh*(curarea->winy-4))/ltexth;
if (barheight<2) barheight=2;
barstart= (lbarstart*(curarea->winy-4))/ltexth + 8;
st->txtscroll.xmin= 5;
st->txtscroll.xmax= 17;
st->txtscroll.ymax= curarea->winy-barstart;
st->txtscroll.ymin= st->txtscroll.ymax - barheight;
CLAMP(st->txtscroll.ymin, 2, curarea->winy-2);
CLAMP(st->txtscroll.ymax, 2, curarea->winy-2);
}
static void draw_stdoutscroll(SpaceStdOut *st)
{
calc_stdout_rcts(st);
BIF_ThemeColorShade(TH_SHADE1, -20);
glRecti(2, 2, 20, curarea->winy-6);
uiEmboss(2, 2, 20, curarea->winy-6, 1);
BIF_ThemeColor(TH_SHADE1);
glRecti(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax);
BIF_ThemeColor(TH_SHADE2);
glRecti(st->txtscroll.xmin, st->txtscroll.ymin, st->txtscroll.xmax, st->txtscroll.ymax);
uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
}
static void screen_skip(SpaceStdOut *st, int lines)
{
int last;
if (!st) return;
if (st->spacetype != SPACE_STDOUT) return;
st->top += lines;
last= txt_get_span(std_text()->lines.first, std_text()->lines.last);
last= last - (st->viewlines/2);
if (st->top>last) st->top= last;
if (st->top<0) st->top= 0;
}
/*
* mode 1 == view scroll
* mode 2 == scrollbar
*/
static void do_stdoutscroll(SpaceStdOut *st, int mode)
{
short delta[2]= {0, 0};
short mval[2], hold[2], old[2];
calc_stdout_rcts(st);
st->flags|= ST_SCROLL_SELECT;
glDrawBuffer(GL_FRONT);
uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
glDrawBuffer(GL_BACK);
getmouseco_areawin(mval);
old[0]= hold[0]= mval[0];
old[1]= hold[1]= mval[1];
while(get_mbut()&(L_MOUSE|M_MOUSE)) {
getmouseco_areawin(mval);
if(old[0]!=mval[0] || old[1]!=mval[1]) {
if (mode==1) {
delta[0]= (hold[0]-mval[0])/spacestdout_get_fontwidth(st);
delta[1]= (mval[1]-hold[1])/st->lheight;
}
else delta[1]= (hold[1]-mval[1])*st->pix_per_line;
if (delta[0] || delta[1]) {
screen_skip(st, delta[1]);
st->left+= delta[0];
if (st->left<0) st->left= 0;
scrarea_do_windraw(curarea);
screen_swapbuffers();
hold[0]=mval[0];
hold[1]=mval[1];
}
old[0]=mval[0];
old[1]=mval[1];
} else {
BIF_wait_for_statechange();
}
}
st->flags^= ST_SCROLL_SELECT;
glDrawBuffer(GL_FRONT);
uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
glDrawBuffer(GL_BACK);
}
static void do_selection(SpaceStdOut *st, int selecting)
{
short mval[2], old[2];
int sell, selc;
int linep2, charp2;
int first= 1;
getmouseco_areawin(mval);
old[0]= mval[0];
old[1]= mval[1];
if (!selecting) {
int curl= txt_get_span(std_text()->lines.first, std_text()->curl);
int curc= std_text()->curc;
int linep2, charp2;
set_cursor_to_pos(st, mval[0], mval[1], 0);
linep2= txt_get_span(std_text()->lines.first, std_text()->curl);
charp2= std_text()->selc;
if (curl!=linep2 || curc!=charp2)
txt_undo_add_toop(std_text(), UNDO_CTO, curl, curc, linep2, charp2);
}
sell= txt_get_span(std_text()->lines.first, std_text()->sell);
selc= std_text()->selc;
while(get_mbut()&L_MOUSE) {
getmouseco_areawin(mval);
if (mval[1]<0 || mval[1]>curarea->winy) {
int d= (old[1]-mval[1])*st->pix_per_line;
if (d) screen_skip(st, d);
set_cursor_to_pos(st, mval[0], mval[1]<0?0:curarea->winy, 1);
scrarea_do_windraw(curarea);
screen_swapbuffers();
} else if (mval[0]<0 || mval[0]>curarea->winx) {
if (mval[0]>curarea->winx) st->left++;
else if (mval[0]<0 && st->left>0) st->left--;
set_cursor_to_pos(st, mval[0], mval[1], 1);
scrarea_do_windraw(curarea);
screen_swapbuffers();
PIL_sleep_ms(10);
} else if (first || old[0]!=mval[0] || old[1]!=mval[1]) {
set_cursor_to_pos(st, mval[0], mval[1], 1);
scrarea_do_windraw(curarea);
screen_swapbuffers();
old[0]= mval[0];
old[1]= mval[1];
first= 1;
} else {
BIF_wait_for_statechange();
}
}
linep2= txt_get_span(std_text()->lines.first, std_text()->sell);
charp2= std_text()->selc;
if (sell!=linep2 || selc!=charp2)
txt_undo_add_toop(std_text(), UNDO_STO, sell, selc, linep2, charp2);
}
void drawstdoutspace(ScrArea *sa, void *spacedata)
{
SpaceStdOut *st= curarea->spacedata.first;
Text *text;
int i;
TextLine *tmp;
float col[3];
int linecount = 0;
BIF_GetThemeColor3fv(TH_BACK, col);
glClearColor(col[0], col[1], col[2], 0.0);
glClear(GL_COLOR_BUFFER_BIT);
myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
draw_area_emboss(sa);
if(st->lheight) st->viewlines= (int) curarea->winy/st->lheight;
else st->viewlines= 0;
stdout_gettext(st);
text= std_text();
/* Make sure all the positional pointers exist */
if (!text->curl || !text->sell || !text->lines.first || !text->lines.last)
txt_clean_text(text);
BIF_ThemeColor(TH_TEXT);
draw_cursor(st);
tmp= text->lines.first;
for (i= 0; i<st->top && tmp; i++) {
tmp= tmp->next;
linecount++;
}
for (i=0; i<st->viewlines && tmp; i++, tmp= tmp->next)
{
if (strncmp(tmp->line, "error: ", 7) != 0)
BIF_ThemeColor(TH_TEXT);
else
BIF_ThemeColor(TH_SYNTAX_B);
stdout_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET, curarea->winy-st->lheight*(i+1), tmp->format);
}
draw_stdoutscroll(st);
curarea->win_swap= WIN_BACK_OK;
}
void pop_space_stdout (SpaceStdOut *st)
{
int i, x;
if(!st) return;
if(!std_text()->curl) return;
i= txt_get_span(std_text()->lines.first, std_text()->curl);
if (st->top+st->viewlines <= i || st->top > i) {
st->top= i - st->viewlines/2;
}
x= stdout_draw(st, std_text()->curl->line, st->left, std_text()->curc, 0, 0, 0, NULL);
if (x==0 || x>curarea->winx) {
st->left= std_text()->curc-0.5*(curarea->winx)/spacestdout_get_fontwidth(st);
}
if (st->top < 0) st->top= 0;
if (st->left <0) st->left= 0;
}
void free_stdoutspace(SpaceStdOut *st)
{
if (!st)
return;
stdout_text = NULL;
}
/*
* again==0 show find panel or find
* again==1 find text again */
void std_find_panel(SpaceStdOut *st, int again)
{
Text *text=std_text();
char *findstr= last_txt_find_string;
if (again==0) {
findstr= txt_sel_to_buf(text);
} else if (again==1) {
char buf[256];
if (findstr && strlen(findstr)<(sizeof(buf)-1))
strcpy(buf, findstr);
else
buf[0]= 0;
if (sbutton(buf, 0, sizeof(buf)-1, "Find: ") && buf[0])
findstr= BLI_strdup(buf);
else
findstr= NULL;
}
if (findstr!=last_txt_find_string) {
if (last_txt_find_string)
MEM_freeN(last_txt_find_string);
last_txt_find_string= findstr;
}
if (findstr) {
if (txt_find_string(text, findstr))
pop_space_stdout(st);
else
error("Not found: %s", findstr);
}
}
static void set_tabs(Text *text)
{
SpaceText *st = curarea->spacedata.first;
st->currtab_set = setcurr_tab(text);
}
void winqreadstdoutspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
{
unsigned short event= evt->event;
short val= evt->val;
char ascii= evt->ascii;
SpaceStdOut *st= curarea->spacedata.first;
Text *text= std_text();
int do_draw=0, p;
/* smartass code to prevent the CTRL/ALT events below from not working! */
if(!ispunct(ascii))
if (!isprint(ascii) || (G.qual & ~LR_SHIFTKEY)) ascii= 0;
if (event==LEFTMOUSE) {
if (val) {
short mval[2];
set_tabs(text);
getmouseco_areawin(mval);
if (mval[0]>2 && mval[0]<20 && mval[1]>2 && mval[1]<curarea->winy-2) {
do_stdoutscroll(st, 2);
} else {
do_selection(st, G.qual&LR_SHIFTKEY);
do_draw= 1;
}
}
} else if (event==MIDDLEMOUSE) {
if (val) {
do_stdoutscroll(st, 1);
}
} else if (val) {
switch (event) {
case AKEY:
if (G.qual & LR_ALTKEY) {
txt_move_bol(text, G.qual & LR_SHIFTKEY);
do_draw= 1;
pop_space_stdout(st);
} else if (G.qual & LR_CTRLKEY) {
txt_sel_all(text);
do_draw= 1;
}
break; /* BREAK A */
case CKEY:
if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
if(G.qual & LR_SHIFTKEY)
txt_copy_clipboard(text);
else
txt_copy_sel(text);
do_draw= 1;
}
break; /* BREAK C */
case EKEY:
if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
switch(pupmenu("Edit %t|Copy %x1")) {
case 0:
txt_copy_sel(text);
do_draw= 1;
break;
}
}
else if (G.qual == LR_CTRLKEY || G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
txt_move_eol(text, G.qual & LR_SHIFTKEY);
do_draw= 1;
pop_space_stdout(st);
}
break; /* BREAK E */
case FKEY:
if (G.qual == LR_ALTKEY) {
if (txt_has_sel(text)) {
std_find_panel(st,0);
do_draw= 1;
}
}
else if (G.qual == (LR_ALTKEY|LR_CTRLKEY)) { /* always search button */
std_find_panel(st,1);
do_draw= 1;
}
break; /* BREAK F */
case QKEY:
if (okee("Quit Blender")) exit_usiblender();
break; /* BREAK Q */
case SKEY:
if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
p= pupmenu("Select %t|"
"Select All %x0|"
"Select Line %x1");
switch(p) {
case 0:
txt_sel_all(text);
do_draw= 1;
break;
case 1:
txt_sel_line(text);
do_draw= 1;
break;
}
}
break; /* BREAK S */
case VKEY:
if (G.qual == (LR_ALTKEY| LR_SHIFTKEY)) {
switch(pupmenu("View %t|Top of Output %x0|Bottom of Output %x1|Page Up %x2|Page Down %x3")) {
case 0:
txt_move_bof(text, 0);
do_draw= 1;
pop_space_stdout(st);
break;
case 1:
txt_move_eof(text, 0);
do_draw= 1;
pop_space_stdout(st);
break;
case 2:
screen_skip(st, -st->viewlines);
do_draw= 1;
break;
case 3:
screen_skip(st, st->viewlines);
do_draw= 1;
break;
}
}
break; /* BREAK V */
case DOWNARROWKEY:
txt_move_down(text, G.qual & LR_SHIFTKEY);
set_tabs(text);
do_draw= 1;
pop_space_stdout(st);
break;
case LEFTARROWKEY:
txt_move_left(text, G.qual & LR_SHIFTKEY);
set_tabs(text);
do_draw= 1;
pop_space_stdout(st);
break;
case RIGHTARROWKEY:
txt_move_right(text, G.qual & LR_SHIFTKEY);
set_tabs(text);
do_draw= 1;
pop_space_stdout(st);
break;
case UPARROWKEY:
txt_move_up(text, G.qual & LR_SHIFTKEY);
set_tabs(text);
do_draw= 1;
pop_space_stdout(st);
break;
case PAGEDOWNKEY:
screen_skip(st, st->viewlines);
do_draw= 1;
break;
case PAGEUPKEY:
screen_skip(st, -st->viewlines);
do_draw= 1;
break;
case HOMEKEY:
txt_move_bol(text, G.qual & LR_SHIFTKEY);
do_draw= 1;
pop_space_stdout(st);
break;
case ENDKEY:
txt_move_eol(text, G.qual & LR_SHIFTKEY);
do_draw= 1;
pop_space_stdout(st);
break;
case WHEELUPMOUSE:
screen_skip(st, -U.wheellinescroll);
do_draw= 1;
break;
case WHEELDOWNMOUSE:
screen_skip(st, U.wheellinescroll);
do_draw= 1;
break;
}
}
if (do_draw) {
ScrArea *sa;
for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
SpaceStdOut *st= sa->spacedata.first;
if (st && st->spacetype==SPACE_STDOUT) {
scrarea_queue_redraw(sa);
}
}
}
}

Event Timeline