4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
28 * All screen functions that are related to the interface
29 * handling and drawing. Might be split up as well later...
40 #include <ctype.h> /* isprint */
44 #include "GHOST_Types.h"
46 #include "MEM_guardedalloc.h"
52 #include "BLI_blenlib.h"
53 #include "BLI_arithb.h"
55 #include "IMB_imbuf_types.h"
56 #include "IMB_imbuf.h"
58 #include "DNA_action_types.h"
59 #include "DNA_object_types.h"
60 #include "DNA_scene_types.h"
61 #include "DNA_screen_types.h"
62 #include "DNA_space_types.h"
63 #include "DNA_sound_types.h"
64 #include "DNA_view3d_types.h"
65 #include "DNA_userdef_types.h"
67 #include "BLO_writefile.h"
69 #include "BKE_utildefines.h"
70 #include "BKE_global.h"
71 #include "BKE_library.h"
73 #include "BKE_blender.h"
74 #include "BKE_screen.h"
77 #include "BKE_verse.h"
80 #include "BIF_cursors.h"
81 #include "BIF_drawscene.h"
82 #include "BIF_editsound.h"
83 #include "BIF_glutil.h"
85 #include "BIF_graphics.h"
86 #include "BIF_interface.h"
87 #include "BIF_interface_icons.h"
88 #include "BIF_mainqueue.h"
89 #include "BIF_mywindow.h"
90 #include "BIF_previewrender.h"
91 #include "BIF_renderwin.h"
92 #include "BIF_retopo.h"
93 #include "BIF_screen.h"
94 #include "BIF_space.h"
95 #include "BIF_toets.h"
96 #include "BIF_toolbox.h"
97 #include "BIF_usiblender.h"
98 #include "BIF_keyval.h"
99 #include "BIF_resources.h"
101 #include "BSE_edit.h"
102 #include "BSE_filesel.h"
103 #include "BSE_headerbuttons.h"
104 #include "BSE_seqaudio.h"
105 #include "BSE_view.h"
107 #ifndef DISABLE_PYTHON
108 #include "BPY_extern.h"
111 #include "mydevice.h"
118 * - WATCH THE EDGES, VERTICES HAVE TO BE IN ORDER...
119 (lowest pointer first). Otherwise unpredictable effects!
120 * - problem: flags here are not nicely implemented. After usage
121 always reset to zero.
124 /* comment added to test orange branch */
126 static void testareas(void);
127 static void area_autoplayscreen(void);
128 static void wait_for_event(void);
131 /* ********* Globals *********** */
133 static Window *mainwin= NULL;
134 static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0, start_maximized= 1;
135 static short dodrawscreen= 1;
136 static ScrArea *areawinar[MAXWIN];
137 static ScrArea *g_activearea= NULL;
138 short winqueue_break= 0;
141 /* prototypes -------------------*/
142 int afterqtest(short win, unsigned short evt);
143 unsigned short screen_qread(short *val, char *ascii);
144 void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii);
145 static void drawscredge_area(ScrArea *sa);
147 /**********************************************************************/
149 extern int textediting;
151 static void screen_set_cursor(bScreen *sc)
154 ScrArea *sa= areawinar[sc->winakt];
156 set_cursor(sa->cursor);
158 set_cursor(CURSOR_STD);
162 void waitcursor(int val)
166 set_cursor(CURSOR_WAIT);
168 screen_set_cursor(G.curscreen);
173 static int choose_cursor(ScrArea *sa)
175 if (sa->spacetype==SPACE_VIEW3D) {
176 if(G.obedit) return CURSOR_EDIT;
177 else if(G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT))
178 return CURSOR_VPAINT;
179 else if(FACESEL_PAINT_TEST) return CURSOR_FACESEL;
180 else if(G.f & G_SCULPTMODE) return CURSOR_EDIT;
181 else if(G.f & G_PARTICLEEDIT) return CURSOR_EDIT;
182 else return CURSOR_STD;
184 else if (sa->spacetype==SPACE_TEXT) {
185 return CURSOR_TEXTEDIT;
192 void wich_cursor(ScrArea *sa)
194 sa->cursor= choose_cursor(sa);
196 /* well... the waitcursor() is not a state, so this call will cancel it out */
197 if(get_cursor()!=CURSOR_WAIT)
198 screen_set_cursor(G.curscreen);
202 void setcursor_space(int spacetype, short cur)
207 for (sc= G.main->screen.first; sc; sc= sc->id.next)
208 for (sa= sc->areabase.first; sa; sa= sa->next)
209 if(sa->spacetype==spacetype)
212 screen_set_cursor(G.curscreen);
216 /* ********* IN/OUT ************* */
218 void getmouseco_sc(short *mval) /* screen coordinates */
223 /* mouse_cursor called during a script (via Window.QHandle) need
224 * this function for getmouseco_areawin to work: */
225 void set_g_activearea(ScrArea *sa)
227 if (sa) g_activearea = sa;
230 void getmouseco_areawin(short *mval) /* internal area coordinates */
234 if(g_activearea && g_activearea->win) {
235 mval[0]-= g_activearea->winrct.xmin;
236 mval[1]-= g_activearea->winrct.ymin;
240 void getmouseco_headwin(short *mval) /* internal area coordinates */
244 if(g_activearea && g_activearea->headwin) {
245 mval[0]-= g_activearea->headrct.xmin;
246 mval[1]-= g_activearea->headrct.ymin;
250 void headerprint(char *str)
252 if(curarea->headertype) {
253 areawinset(curarea->headwin);
257 BIF_ThemeColor(TH_MENU_TEXT); /* better than cpack(0x0) color no? (desoto) */
258 glRasterPos2i(20+curarea->headbutofs, 6);
259 BMF_DrawString(G.font, str);
261 curarea->head_swap= WIN_BACK_OK;
262 areawinset(curarea->win);
265 // dunno... thats for later (ton)
269 /* *********** STUFF ************** */
271 static int scredge_is_horizontal(ScrEdge *se)
273 return (se->v1->vec.y == se->v2->vec.y);
276 static ScrEdge *screen_find_active_scredge(bScreen *sc, short *mval)
280 for (se= sc->edgebase.first; se; se= se->next) {
281 if (scredge_is_horizontal(se)) {
283 min= MIN2(se->v1->vec.x, se->v2->vec.x);
284 max= MAX2(se->v1->vec.x, se->v2->vec.x);
286 if (abs(mval[1]-se->v1->vec.y)<=2 && mval[0] >= min && mval[0]<=max)
291 min= MIN2(se->v1->vec.y, se->v2->vec.y);
292 max= MAX2(se->v1->vec.y, se->v2->vec.y);
294 if (abs(mval[0]-se->v1->vec.x)<=2 && mval[1] >= min && mval[1]<=max)
302 void areawinset(short win)
305 curarea= areawinar[win];
307 printf("error in areawinar %d ,areawinset\n", win);
311 BIF_SetTheme(curarea);
313 switch(curarea->spacetype) {
315 G.vd= curarea->spacedata.first;
318 G.sipo= curarea->spacedata.first;
322 G.buts= curarea->spacedata.first;
326 SpaceSeq *sseq= curarea->spacedata.first;
331 G.soops= curarea->spacedata.first;
332 G.v2d= &G.soops->v2d;
335 G.sima= curarea->spacedata.first;
339 G.ssound= curarea->spacedata.first;
340 G.v2d= &G.ssound->v2d;
343 G.saction= curarea->spacedata.first;
344 G.v2d= &G.saction->v2d;
347 G.snla= curarea->spacedata.first;
352 SpaceTime *stime= curarea->spacedata.first;
358 SpaceNode *snode= curarea->spacedata.first;
364 SpaceImaSel *simasel= curarea->spacedata.first;
365 G.v2d= &simasel->v2d;
372 if(win) mywinset(win);
375 #define SCR_BACK 0.55
378 void headerbox(ScrArea *area)
380 float width= area->winx;
383 glClearColor(SCR_BACK, SCR_BACK, SCR_BACK, 0.0);
384 glClear(GL_COLOR_BUFFER_BIT);
386 active= area_is_active_area(area);
388 if(active) BIF_ThemeColor(TH_HEADER);
389 else BIF_ThemeColor(TH_HEADERDESEL);
391 /* weird values here... is because of window matrix that centers buttons */
392 if(area->headertype==HEADERTOP) {
394 uiRoundBoxEmboss(-0.5+area->headbutofs, -10.0, width-1.5+area->headbutofs, HEADERY-2.0, SCR_ROUND, active);
398 uiRoundBoxEmboss(-0.5+area->headbutofs, -3.5, width-1.5+area->headbutofs, HEADERY+10, SCR_ROUND, active);
404 int area_is_active_area(ScrArea *area)
406 return (g_activearea && area==g_activearea);
409 void scrarea_do_headdraw(ScrArea *area)
411 if (area->headertype) {
412 areawinset(area->headwin);
416 /* we make scissor test slightly smaller not to destroy rounded headers */
417 glScissor(area->headrct.xmin+5, area->headrct.ymin, area->winx-10, HEADERY);
419 switch(area->spacetype) {
420 case SPACE_FILE: file_buttons(); break;
421 case SPACE_INFO: info_buttons(); break;
422 case SPACE_VIEW3D: view3d_buttons(); break;
423 case SPACE_IPO: ipo_buttons(); break;
424 case SPACE_BUTS: buts_buttons(); break;
425 case SPACE_SEQ: seq_buttons(); break;
426 case SPACE_IMAGE: image_buttons(); break;
427 case SPACE_IMASEL: imasel_buttons(); break;
428 case SPACE_OOPS: oops_buttons(); break;
429 case SPACE_TEXT: text_buttons(); break;
430 case SPACE_SCRIPT:script_buttons(); break;
431 case SPACE_SOUND: sound_buttons(); break;
432 case SPACE_ACTION: action_buttons(); break;
433 case SPACE_NLA: nla_buttons(); break;
434 case SPACE_TIME: time_buttons(area); break;
435 case SPACE_NODE: node_buttons(area); break;
439 //glScissor(area->winrct.xmin, area->winrct.xmax, area->winx, area->winy);
440 area->head_swap= WIN_BACK_OK;
443 void scrarea_do_headchange(ScrArea *area)
445 float ofs= area->headbutofs;
447 if (area->headertype==HEADERDOWN) {
448 bwin_ortho2(area->headwin, -0.375+ofs, area->headrct.xmax-area->headrct.xmin-0.375+ofs, -3.375, area->headrct.ymax-area->headrct.ymin-3.375+1.0);
449 } else if (area->headertype==HEADERTOP) {
450 bwin_ortho2(area->headwin, -0.375+ofs, area->headrct.xmax-area->headrct.xmin-0.375+ofs, -2.375-1.0, area->headrct.ymax-area->headrct.ymin-2.375);
455 static void openheadwin(ScrArea *sa);
456 static void closeheadwin(ScrArea *sa);
458 static void scrarea_change_headertype(ScrArea *sa, int newtype)
460 sa->headertype= newtype;
464 uiFreeBlocksWin(&sa->uiblocks, sa->headwin);
474 mainqenter(DRAWEDGES, 1);
478 static void headmenu(ScrArea *sa)
480 short val= pupmenu("Header %t|Top%x2|Bottom %x1|No Header %x0");
483 scrarea_change_headertype(sa, val);
487 static void addqueue_ext(short win, unsigned short event, short val, char ascii)
489 if (win<4 || !areawinar[win]) {
490 /* other win ids are for mainwin & renderwin */
495 memset(&evt, 0, sizeof(evt));
500 bwin_qadd(win, &evt);
504 void addqueue(short win, unsigned short event, short val)
506 addqueue_ext(win, event, val, 0);
509 void scrarea_queue_winredraw(ScrArea *area)
511 addqueue(area->win, REDRAW, 1);
513 void scrarea_queue_headredraw(ScrArea *area)
515 if (area->headwin) addqueue(area->headwin, REDRAW, 1);
517 void scrarea_queue_redraw(ScrArea *area)
519 scrarea_queue_winredraw(area);
520 scrarea_queue_headredraw(area);
523 static void scrollheader(ScrArea *area);
524 static void scrarea_dispatch_header_events(ScrArea *sa)
528 short do_redraw=0, do_change=0;
530 areawinset(sa->headwin);
532 while(bwin_qread(sa->headwin, &evt)) {
534 if( uiDoBlocks(&curarea->uiblocks, evt.event, 1)!=UI_NOTHING ) evt.event= 0;
538 do_headerbuttons(evt.val);
542 if (G.qual & LR_CTRLKEY) {
543 window_lower(mainwin);
545 window_raise(mainwin);
564 if (winqueue_break == 0) {
565 scrarea_do_winhandle(sa, &evt);
566 if (winqueue_break == 0) areawinset(sa->headwin);
570 if(winqueue_break) return;
574 /* test: does window still exist? */
575 tempsa= areawinar[sa->headwin];
576 if(tempsa==0) return;
578 /* this functional separation does not work as well as i expected... */
579 if(do_change) scrarea_do_headchange(sa);
580 if(do_redraw) scrarea_do_headdraw(sa);
583 static void scrarea_dispatch_events(ScrArea *sa)
587 short do_redraw=0, do_change=0;
589 if(sa!=curarea || sa->win!=mywinget()) areawinset(sa->win);
591 while(bwin_qread(sa->win, &evt)) {
592 if(evt.event==REDRAW) {
595 else if(evt.event==CHANGED) {
601 scrarea_do_winhandle(sa, &evt);
604 if(winqueue_break) return;
607 /* test: does window still exist */
608 tempsa= areawinar[sa->win];
609 if(tempsa==0) return;
611 if (do_change || do_redraw) {
614 scrarea_do_winchange(curarea);
616 scrarea_do_windraw(curarea);
626 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
628 scrarea_queue_winredraw(sa);
629 sa->win_swap &= ~WIN_FRONT_OK;
632 scrarea_queue_headredraw(sa);
633 sa->head_swap &= ~WIN_FRONT_OK;
639 void markdirty_all_back(void)
643 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
645 sa->win_swap &= ~WIN_BACK_OK;
648 sa->head_swap &= ~WIN_BACK_OK;
652 /* if needed; backbuffer selection redraw */
653 if(G.vd) G.vd->flag |= V3D_NEEDBACKBUFDRAW;
657 void markdirty_win_back(short winid)
659 ScrArea *sa= areawinar[winid];
661 if(sa->win==winid) sa->win_swap &= ~WIN_BACK_OK;
662 else sa->head_swap &= ~WIN_BACK_OK;
667 int is_allowed_to_change_screen(bScreen *new)
669 /* not when curscreen is full
670 * not when obedit && old->scene!=new->scene
674 if(G.curscreen->full != SCREENNORMAL) return 0;
675 if(curarea->full) return 0;
677 if(G.curscreen->scene!=new->scene) return 0;
682 void splash(void *data, int datasize, char *string)
688 bbuf= IMB_ibImageFromMemory((int *)data, datasize, IB_rect);
692 mywinset(G.curscreen->mainwin);
699 maxy = MIN2(bbuf->y, 18);
701 for (y = 0; y < maxy; y++) {
702 for (x = 0; x < bbuf->x; x++) {
708 glDrawBuffer(GL_FRONT);
710 uiDrawBoxShadow(200, (prefsizx-bbuf->x)/2, (prefsizy-bbuf->y)/2, (prefsizx+bbuf->x)/2, (prefsizy+bbuf->y)/2);
712 glRasterPos2i((prefsizx-bbuf->x)/2, (prefsizy-bbuf->y)/2);
713 glDrawPixels(bbuf->x, bbuf->y, GL_RGBA, GL_UNSIGNED_BYTE, bbuf->rect);
719 if (BMF_GetStringWidth(font= G.font, string) > bbuf->x)
720 if (BMF_GetStringWidth(font= G.fonts, string) > bbuf->x)
723 width= BMF_GetStringWidth(font, string);
726 glRasterPos2i((prefsizx-width)/2, (prefsizy-bbuf->y)/2 + 6);
727 BMF_DrawString(font, string);
731 glDrawBuffer(GL_BACK);
735 // flush input buffers ....
736 // this might break some things
739 BIF_wait_for_statechange();
749 mainqenter(DRAWEDGES, 1);
753 static void moveareas(ScrEdge *edge);
754 static void joinarea_interactive(ScrArea *area, ScrEdge *onedge);
755 static void splitarea_interactive(ScrArea *area, ScrEdge *onedge);
756 static ScrArea *test_edge_area(ScrArea *sa, ScrEdge *se);
757 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2);
759 static int isjoinable(ScrArea *area, ScrEdge *onedge)
761 struct ScrArea *sa1 = area, *sa2;
764 sa1 = test_edge_area(sa1, onedge);
767 /* find directions with same edge */
768 sa2= G.curscreen->areabase.first;
771 se= screen_findedge(G.curscreen, sa2->v1, sa2->v2);
772 if(onedge==se) return 1;
773 se= screen_findedge(G.curscreen, sa2->v2, sa2->v3);
774 if(onedge==se) return 1;
775 se= screen_findedge(G.curscreen, sa2->v3, sa2->v4);
776 if(onedge==se) return 1;
777 se= screen_findedge(G.curscreen, sa2->v4, sa2->v1);
778 if(onedge==se) return 1;
786 static void screen_edge_edit_event(ScrArea *actarea, ScrEdge *actedge, short evt, short val)
789 // don't allow users to edit full screens
790 if (actarea && actarea->full)
793 if (evt==LEFTMOUSE) {
795 } else if (evt==MIDDLEMOUSE || evt==RIGHTMOUSE) {
797 char str[64] = "Split Area%x1|";
799 if(isjoinable(actarea, actedge)) strcat(str, "Join Areas%x2|");
800 if (actarea->headertype) strcat(str, "No Header%x3");
801 else strcat(str, "Add Header%x3");
803 edgeop= pupmenu(str);
804 if (edgeop==1) splitarea_interactive(actarea, actedge);
805 else if (edgeop==2) joinarea_interactive(actarea, actedge);
806 else if (edgeop==3) scrarea_change_headertype(actarea,
807 actarea->headertype?0:HEADERDOWN);
809 else blenderqread(evt, val); // global hotkeys
815 extern void mywindow_init_mainwin(Window *win, int orx, int ory, int sizex, int sizey);
816 void test_scale_screen(bScreen *);
818 static void resize_screens(int x, int y, int w, int h) {
824 test_scale_screen(G.curscreen);
828 static void init_mainwin(void)
830 int orx, ory, sizex, sizey;
832 glEnable(GL_SCISSOR_TEST);
834 window_get_position(mainwin, &orx, &ory);
835 window_get_size(mainwin, &sizex, &sizey);
837 /* XXX, temporary stupid fix for minimize at windows */
838 if (!sizex && !sizey) {
842 mywindow_init_mainwin(mainwin, orx, ory, sizex, sizey);
843 resize_screens(orx, ory, sizex, sizey);
848 static short afterqueue[MAXQUEUE][3];
849 static int nafterqitems= 0;
851 void addafterqueue(short win, unsigned short evt, short val)
853 if (nafterqitems<MAXQUEUE) {
856 /* only one afterqueue event of each type */
857 for(a=0; a<nafterqitems; a++) {
858 if(afterqueue[a][0]==win && afterqueue[a][1]==evt) {
859 afterqueue[a][2]= val;
863 afterqueue[nafterqitems][0]= win;
864 afterqueue[nafterqitems][1]= evt;
865 afterqueue[nafterqitems][2]= val;
870 static void append_afterqueue(void)
872 while (nafterqitems) {
873 short win= afterqueue[nafterqitems-1][0];
874 unsigned short evt= afterqueue[nafterqitems-1][1];
875 short val= afterqueue[nafterqitems-1][2];
877 addqueue(win, evt, val);
883 /* check for event in afterqueue, used in force_draw in space.c */
884 int afterqtest(short win, unsigned short evt)
888 for(a=0; a<nafterqitems; a++) {
889 if(afterqueue[a][0]==win && afterqueue[a][1]==evt) return 1;
895 static char ext_load_str[256]= {0, 0};
897 static short ext_reshape= 0, ext_redraw=0, ext_inputchange=0, ext_mousemove=0, ext_undopush=0;
899 static void flush_extqd_events(void) {
900 if (ext_inputchange) {
901 mainqenter(INPUTCHANGE, ext_inputchange);
902 } else if (ext_reshape) {
903 mainqenter(RESHAPE, ext_redraw);
904 } else if (ext_redraw) {
905 mainqenter(REDRAW, ext_redraw);
906 } else if (ext_undopush) {
907 mainqenter(UNDOPUSH, ext_undopush);
908 } else if (ext_mousemove) {
911 getmouseco_sc(mouse);
913 mainqenter(MOUSEX, mouse[0]);
914 mainqenter(MOUSEY, mouse[1]);
917 ext_inputchange= ext_reshape= ext_redraw= ext_mousemove= ext_undopush= 0;
923 winlay_process_events(0);
929 /* return true if events are waiting anywhere */
934 if (nafterqitems || qtest()) return 1;
936 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
937 if (bwin_qtest(sa->win)) return 1;
938 if (sa->headwin && bwin_qtest(sa->headwin)) return 1;
944 static void wait_for_event(void)
946 while (!mainqtest()) {
947 winlay_process_events(1);
951 unsigned short screen_qread(short *val, char *ascii)
953 unsigned short event;
957 event= mainqread(val, ascii);
959 if(event==RIGHTSHIFTKEY || event==LEFTSHIFTKEY) {
960 if(*val) G.qual |= LR_SHIFTKEY;
961 else G.qual &= ~LR_SHIFTKEY;
963 else if(event==RIGHTALTKEY || event==LEFTALTKEY) {
964 if(*val) G.qual |= LR_ALTKEY;
965 else G.qual &= ~LR_ALTKEY;
967 else if(event==RIGHTCTRLKEY || event==LEFTCTRLKEY) {
968 if(*val) G.qual |= LR_CTRLKEY;
969 else G.qual &= ~LR_CTRLKEY;
971 else if(event==COMMANDKEY) { // OSX
972 if(*val) G.qual |= LR_COMMANDKEY;
973 else G.qual &= ~LR_COMMANDKEY;
979 unsigned short extern_qread_ext(short *val, char *ascii)
981 /* stores last INPUTCHANGE and last REDRAW */
982 unsigned short event;
984 event= screen_qread(val, ascii);
985 if(event==RESHAPE) ext_reshape= *val;
986 else if(event==REDRAW) ext_redraw= *val;
987 else if(event==UNDOPUSH) ext_undopush= *val;
988 else if(event==INPUTCHANGE) ext_inputchange= *val;
989 else if(event==MOUSEY || event==MOUSEX) ext_mousemove= 1;
990 else if((G.qual & (LR_CTRLKEY|LR_ALTKEY)) && event==F3KEY) {
993 return ESCKEY; /* go out of menu, if that was set */
999 unsigned short extern_qread(short *val)
1002 return extern_qread_ext(val, &ascii);
1005 int blender_test_break(void)
1007 if (!G.background) {
1008 static double ltime= 0;
1009 double curtime= PIL_check_seconds_timer();
1011 /* only check for breaks every 10 milliseconds
1012 * if we get called more often.
1014 if ((curtime-ltime)>.001) {
1019 if (extern_qread(&val) == ESCKEY) {
1026 return (G.afbreek==1);
1029 void reset_autosave(void)
1031 if(U.flag & USER_AUTOSAVE) {
1032 window_set_timer(mainwin, U.savetime*60*1000, AUTOSAVE_FILE);
1036 /* ************ handlers ************** */
1038 /* don't know yet how the handlers will evolve, for simplicity
1039 i choose for an array with eventcodes, this saves in a file!
1041 void add_screenhandler(bScreen *sc, short eventcode, short val)
1046 for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
1047 if( sc->handler[a]==eventcode ) {
1048 sc->handler[a+1]= val;
1051 else if( sc->handler[a]==0) {
1052 sc->handler[a]= eventcode;
1053 sc->handler[a+1]= val;
1057 if(a==SCREEN_MAXHANDLER) printf("error; max (4) screen handlers reached!\n");
1060 void rem_screenhandler(bScreen *sc, short eventcode)
1064 for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
1065 if( sc->handler[a]==eventcode) {
1072 int has_screenhandler(bScreen *sc, short eventcode)
1076 for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
1077 if( sc->handler[a]==eventcode) {
1084 static void animated_screen(bScreen *sc, short val)
1086 if ((val & TIME_WITH_SEQ_AUDIO)) {
1090 audiostream_start( CFRA );
1093 int cfra = audiostream_pos();
1094 if(cfra <= CFRA) CFRA++;
1100 if(CFRA > PEFRA) CFRA= PSFRA;
1103 update_for_newframe_nodraw(1);
1105 if(val & TIME_ALL_3D_WIN)
1106 allqueue(REDRAWVIEW3D, 0);
1107 else if(val & TIME_LEFTMOST_3D_WIN) {
1108 ScrArea *sa= sc->areabase.first, *samin=NULL;
1110 for(; sa; sa= sa->next) {
1111 if(sa->spacetype==SPACE_VIEW3D) {
1112 if(sa->winrct.xmin - sa->winrct.ymin < min) {
1114 min= sa->winrct.xmin - sa->winrct.ymin;
1118 if(samin) scrarea_queue_winredraw(samin);
1120 if(val & TIME_ALL_ANIM_WIN) allqueue(REDRAWANIM, 0);
1121 if(val & TIME_ALL_BUTS_WIN) allqueue(REDRAWBUTSALL, 0);
1122 if(val & TIME_SEQ) {
1123 allqueue(REDRAWSEQ, 0);
1126 allqueue(REDRAWTIME, 0);
1129 /* because we still have to cope with subloops, this function is called
1130 in viewmove() for example too */
1132 /* returns 1 if something was handled */
1133 /* restricts to frames-per-second setting for frequency of updates */
1134 int do_screenhandlers(bScreen *sc)
1136 static double ltime=0.0;
1137 double swaptime, time;
1140 time = PIL_check_seconds_timer();
1143 /* only now do the handlers */
1144 if(swaptime < time-ltime || ltime==0.0) {
1148 for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
1149 switch(sc->handler[a]) {
1150 case SCREEN_HANDLER_ANIM:
1151 animated_screen(sc, sc->handler[a+1]);
1154 case SCREEN_HANDLER_PYTHON:
1157 case SCREEN_HANDLER_VERSE:
1167 else if( qtest()==0) PIL_sleep_ms(5); // 5 milliseconds pause, for idle
1169 /* separate check for if we need to add to afterqueue */
1170 /* is only to keep mainqueue awqke */
1171 for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
1172 if(sc->handler[a]) {
1173 ScrArea *sa= sc->areabase.first;
1174 if(sa->headwin) addafterqueue(sa->headwin, SCREEN_HANDLER, 1);
1175 else addafterqueue(sa->win, SCREEN_HANDLER, 1);
1182 /* ****** end screen handlers ************ */
1184 static void drawscreen(void)
1188 mywinset(G.curscreen->mainwin);
1189 myortho2(-0.375, (float)G.curscreen->sizex-0.375, -0.375, (float)G.curscreen->sizey-0.375);
1191 sa= G.curscreen->areabase.first;
1193 drawscredge_area(sa);
1197 /* this double draw patch seems to be needed for certain sgi's (octane, indigo2) */
1198 #if defined(__sgi) || defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__)
1199 glDrawBuffer(GL_FRONT);
1201 sa= G.curscreen->areabase.first;
1203 drawscredge_area(sa);
1207 glDrawBuffer(GL_BACK);
1211 static void screen_dispatch_events(void) {
1212 int events_remaining= 1;
1215 window_make_active(mainwin); // added it here instead of screenmain (ton)
1217 while (events_remaining) {
1218 events_remaining= 0;
1221 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1222 /* first check header, then rest. Header sometimes has initialization code */
1223 if (sa->headwin && bwin_qtest(sa->headwin)) {
1224 scrarea_dispatch_header_events(sa);
1225 events_remaining= 1;
1227 if (winqueue_break) break;
1229 if (bwin_qtest(sa->win)) {
1230 scrarea_dispatch_events(sa);
1231 events_remaining= 1;
1233 if (winqueue_break) break;
1236 if (winqueue_break) break;
1239 /* winqueue_break isnt the best of all solutions... but it is called on switching screens,
1240 so drawing should wait for all redraw/init events to be handled */
1241 if (winqueue_break==0) {
1247 screen_swapbuffers();
1248 do_screenhandlers(G.curscreen);
1252 static ScrArea *screen_find_area_for_pt(bScreen *sc, short *mval)
1256 /* hotspot area of 1 pixel extra */
1258 for (sa= sc->areabase.first; sa; sa= sa->next) {
1259 if( sa->totrct.xmin + 1 < mval[0] )
1260 if( sa->totrct.ymin + 1 < mval[1] )
1261 if( sa->totrct.xmax - 1 > mval[0] )
1262 if( sa->totrct.ymax - 1 > mval[1] )
1268 /* ugly yah, will disappear on better event system */
1269 /* is called from interface.c after button events */
1270 static char delayed_undo_name[64];
1271 void screen_delayed_undo_push(char *name)
1273 strncpy(delayed_undo_name, name, 63);
1274 mainqenter(UNDOPUSH, 1);
1277 void screenmain(void)
1281 int onload_script = 0;
1283 window_make_active(mainwin);
1286 unsigned short event;
1290 flush_extqd_events();
1291 if (nafterqitems && !qtest()) {
1292 append_afterqueue();
1293 event= val= ascii= 0;
1295 event= screen_qread(&val, &ascii);
1298 // window_make_active(mainwin); // (only for inputchange, removed, (ton))
1300 if (event==INPUTCHANGE) {
1301 window_make_active(mainwin);
1305 /* If the main window is active, find the current active ScrArea
1306 * underneath the mouse cursor, updating the headers & cursor for
1307 * the appropriate internal window if things have changed.
1309 * If the main window is not active, deactivate the internal
1312 if (has_input || g_activearea==NULL || G.curscreen->winakt) {
1313 ScrArea *newactarea;
1317 getmouseco_sc(mval);
1318 newactarea= screen_find_area_for_pt(G.curscreen, mval);
1321 if (BLI_in_rcti(&newactarea->headrct, mval[0], mval[1])) {
1322 newactwin= newactarea->headwin;
1323 set_cursor(CURSOR_STD);
1325 newactwin= newactarea->win;
1331 if (newactarea && (newactarea != g_activearea)) {
1332 if (g_activearea) scrarea_queue_headredraw(g_activearea);
1333 scrarea_queue_headredraw(newactarea);
1334 if (!(BLI_in_rcti(&newactarea->headrct, mval[0], mval[1]))) /* header always gets std cursor */
1335 set_cursor(newactarea->cursor);
1336 g_activearea= newactarea;
1338 /* when you move mouse from header to window, buttons can remain hilited otherwise */
1339 if(newactwin != G.curscreen->winakt) {
1340 if (g_activearea) scrarea_queue_headredraw(g_activearea);
1342 G.curscreen->winakt= newactwin;
1344 if (G.curscreen->winakt) {
1345 areawinset(G.curscreen->winakt);
1346 if (!(BLI_in_rcti(&newactarea->headrct, mval[0], mval[1]))) /* header always gets std cursor */
1347 set_cursor(choose_cursor(g_activearea));
1352 scrarea_queue_headredraw(g_activearea);
1355 G.curscreen->winakt= 0;
1359 if (event==WINCLOSE) {
1362 else if (event==DRAWEDGES) {
1365 else if (event==RESHAPE) {
1370 else if (event==REDRAW) {
1374 else if( event==UNDOPUSH) {
1375 BIF_undo_push(delayed_undo_name);
1377 else if (event==AUTOSAVE_FILE) {
1378 BIF_write_autosave();
1380 else if (event==LOAD_FILE) {
1381 BIF_read_file(ext_load_str);
1382 sound_initialize_sounds();
1384 #ifndef DISABLE_PYTHON
1385 else if ((event==ONLOAD_SCRIPT) && BPY_has_onload_script()) {
1386 /* event queued in setup_app_data() in blender.c, where G.f is checked */
1388 firsttime = 1; /* see last 'if' in this function */
1395 if (!g_activearea) {
1398 else if (event==QKEY) {
1399 /* Temp place to print mem debugging info ctrl+alt+shift + qkey */
1400 if ( G.qual == (LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
1401 MEM_printmemlist_stats();
1404 else if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT);
1406 if(val && (G.qual == LR_CTRLKEY)) {
1407 if(okee("Quit Blender")) exit_usiblender();
1412 else if (event==RIGHTARROWKEY) {
1413 if(textediting==0 && val && (G.qual & LR_CTRLKEY)) {
1414 bScreen *sc= G.curscreen->id.next;
1416 /* if screen is last, set it to first */
1418 sc= G.main->screen.first;
1420 if(is_allowed_to_change_screen(sc)) setscreen(sc);
1425 else if (event==LEFTARROWKEY) {
1426 if(textediting==0 && val && (G.qual & LR_CTRLKEY)) {
1427 bScreen *sc= G.curscreen->id.prev;
1429 /* if screen is first, set it to last */
1431 sc= G.main->screen.last;
1433 if(is_allowed_to_change_screen(sc)) setscreen(sc);
1438 else if (!G.curscreen->winakt) {
1442 getmouseco_sc(mval);
1443 actedge= screen_find_active_scredge(G.curscreen, mval);
1446 if (scredge_is_horizontal(actedge)) {
1447 set_cursor(CURSOR_Y_MOVE);
1449 set_cursor(CURSOR_X_MOVE);
1451 // this does global hotkeys too
1452 screen_edge_edit_event(g_activearea, actedge, event, val);
1454 set_cursor(CURSOR_STD);
1459 else if (event==ZKEY) {
1460 if(val && G.qual==(LR_ALTKEY|LR_SHIFTKEY|LR_CTRLKEY)) {
1461 extern void set_debug_swapbuffers_ovveride(bScreen *sc, int mode);
1463 int which= pupmenu("Swapbuffers%t|Simple|Debug|DebugSwap|Redraw|Default|KillSwap");
1466 case 1: set_debug_swapbuffers_ovveride(G.curscreen, 's'); break;
1467 case 2: set_debug_swapbuffers_ovveride(G.curscreen, 'd'); break;
1468 case 3: set_debug_swapbuffers_ovveride(G.curscreen, 'f'); break;
1469 case 4: set_debug_swapbuffers_ovveride(G.curscreen, 'r'); break;
1470 case 5: set_debug_swapbuffers_ovveride(G.curscreen, 0); break;
1473 g_activearea->head_swap= 0;
1474 g_activearea->win_swap= 0;
1481 else if (event==SPACEKEY) {
1482 if ((g_activearea->spacetype!=SPACE_TEXT) &&
1483 ( !((g_activearea->spacetype==SPACE_VIEW3D) && ((G.obedit) && G.obedit->type==OB_FONT)) ) &&
1485 (G.qual & LR_SHIFTKEY)) {
1491 if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT||g_activearea->spacetype==SPACE_SEQ);
1492 else if(G.qual==0) {
1493 if(val) toolbox_n();
1498 else if(ELEM(event, UPARROWKEY, DOWNARROWKEY)) {
1499 if(val && (G.qual & LR_CTRLKEY)) {
1506 if (towin && event) {
1507 if (blenderqread(event, val)) // the global keys
1508 addqueue_ext(G.curscreen->winakt, event, val, ascii);
1511 /* only process subwindow queue's once the
1512 * main queue has been emptyied.
1515 if (event==0 || event==EXECUTE) {
1516 screen_dispatch_events();
1520 GLenum error = glGetError();
1522 printf("GL error: %s\n", gluErrorString(error));
1524 /* Bizar hack. The event queue has mutated... */
1525 if ( (firsttime) && (event == 0) ) {
1526 #ifndef DISABLE_PYTHON
1527 if (onload_script) {
1528 /* OnLoad scriptlink */
1529 BPY_do_pyscript(&G.scene->id, SCRIPT_ONLOAD);
1533 if (G.fileflags & G_FILE_AUTOPLAY) {
1534 // SET AUTOPLAY in G.flags for
1537 G.flags |= G_FILE_AUTOPLAY;
1538 area_autoplayscreen();
1540 // Let The Games Begin
1541 // fake a 'p' keypress
1543 mainqenter(PKEY, 1);
1545 extern char datatoc_splash_jpg[];
1546 extern int datatoc_splash_jpg_size;
1548 //if (! ((G.main->versionfile >= G.version)
1549 // || G.save_over)) {
1550 splash((void *)datatoc_splash_jpg,
1551 datatoc_splash_jpg_size, NULL);
1560 //#ifdef _WIN32 // FULLSCREEN
1561 void mainwindow_toggle_fullscreen(int fullscreen)
1563 if (fullscreen) U.uiflag |= USER_FLIPFULLSCREEN;
1564 else U.uiflag &= ~USER_FLIPFULLSCREEN;
1566 window_toggle_fullscreen(mainwin, fullscreen);
1570 void mainwindow_raise(void)
1573 window_raise(mainwin);
1576 void mainwindow_make_active(void)
1579 window_make_active(mainwin);
1582 void mainwindow_close(void)
1585 window_destroy(mainwin);
1589 void mainwindow_set_filename_to_title(char *filename)
1591 char str[FILE_MAXDIR + FILE_MAXFILE];
1592 char dir[FILE_MAXDIR];
1593 char file[FILE_MAXFILE];
1595 BLI_split_dirfile_basic(filename, dir, file);
1597 if(BLI_streq(file, ".B.blend") || filename[0] =='\0')
1598 sprintf(str, "Blender");
1600 sprintf(str, "Blender [%s]", filename);
1602 window_set_title(mainwin, str);
1605 /* ********* AREAS ************* */
1607 void setprefsize(int stax, int stay, int sizx, int sizy, int maximized)
1609 int scrwidth, scrheight;
1611 winlay_get_screensize(&scrwidth, &scrheight);
1613 if(sizx<320) sizx= 320;
1614 if(sizy<256) sizy= 256;
1616 if(stay+sizy>scrheight) {
1617 fprintf(stderr," height prob \n");
1618 sizy= scrheight-stay;
1621 if(sizx<320 || sizy<256) {
1622 printf("ERROR: illegal prefsize\n");
1631 start_maximized= maximized;
1635 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
1637 ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
1641 BLI_addtail(&sc->vertbase, sv);
1645 static void sortscrvert(ScrVert **v1, ScrVert **v2)
1656 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1658 ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
1660 sortscrvert(&v1, &v2);
1664 BLI_addtail(&sc->edgebase, se);
1668 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1672 sortscrvert(&v1, &v2);
1673 for (se= sc->edgebase.first; se; se= se->next)
1674 if(se->v1==v1 && se->v2==v2)
1680 static void removedouble_scrverts(void)
1686 verg= G.curscreen->vertbase.first;
1688 if(verg->newv==0) { /* !!! */
1691 if(v1->newv==0) { /* !?! */
1692 if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
1693 /* printf("doublevert\n"); */
1703 /* replace pointers in edges and faces */
1704 se= G.curscreen->edgebase.first;
1706 if(se->v1->newv) se->v1= se->v1->newv;
1707 if(se->v2->newv) se->v2= se->v2->newv;
1708 /* edges changed: so.... */
1709 sortscrvert(&(se->v1), &(se->v2));
1712 sa= G.curscreen->areabase.first;
1714 if(sa->v1->newv) sa->v1= sa->v1->newv;
1715 if(sa->v2->newv) sa->v2= sa->v2->newv;
1716 if(sa->v3->newv) sa->v3= sa->v3->newv;
1717 if(sa->v4->newv) sa->v4= sa->v4->newv;
1722 verg= G.curscreen->vertbase.first;
1726 BLI_remlink(&G.curscreen->vertbase, verg);
1734 static void removenotused_scrverts(void)
1739 /* we assume edges are ok */
1741 se= G.curscreen->edgebase.first;
1748 sv= G.curscreen->vertbase.first;
1752 BLI_remlink(&G.curscreen->vertbase, sv);
1760 static void removedouble_scredges(void)
1762 ScrEdge *verg, *se, *sn;
1765 verg= G.curscreen->edgebase.first;
1770 if(verg->v1==se->v1 && verg->v2==se->v2) {
1771 BLI_remlink(&G.curscreen->edgebase, se);
1780 static void removenotused_scredges(void)
1786 /* sets flags when edge is used in area */
1787 sa= G.curscreen->areabase.first;
1789 se= screen_findedge(G.curscreen, sa->v1, sa->v2);
1790 if(se==0) printf("error: area %d edge 1 bestaat niet\n", a);
1792 se= screen_findedge(G.curscreen, sa->v2, sa->v3);
1793 if(se==0) printf("error: area %d edge 2 bestaat niet\n", a);
1795 se= screen_findedge(G.curscreen, sa->v3, sa->v4);
1796 if(se==0) printf("error: area %d edge 3 bestaat niet\n", a);
1798 se= screen_findedge(G.curscreen, sa->v4, sa->v1);
1799 if(se==0) printf("error: area %d edge 4 bestaat niet\n", a);
1804 se= G.curscreen->edgebase.first;
1808 BLI_remlink(&G.curscreen->edgebase, se);
1816 void calc_arearcts(ScrArea *sa)
1819 if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1;
1820 else sa->totrct.xmin= sa->v1->vec.x;
1821 if(sa->v4->vec.x<G.curscreen->sizex-1) sa->totrct.xmax= sa->v4->vec.x-1;
1822 else sa->totrct.xmax= sa->v4->vec.x;
1824 if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1;
1825 else sa->totrct.ymin= sa->v1->vec.y;
1826 if(sa->v2->vec.y<G.curscreen->sizey-1) sa->totrct.ymax= sa->v2->vec.y-1;
1827 else sa->totrct.ymax= sa->v2->vec.y;
1829 sa->winrct= sa->totrct;
1830 sa->headrct= sa->totrct;
1831 if(sa->headertype) {
1832 if(sa->headertype==HEADERDOWN) {
1833 sa->headrct.ymax= sa->headrct.ymin+HEADERY;
1834 sa->winrct.ymin= sa->headrct.ymax+1;
1836 else if(sa->headertype==HEADERTOP) {
1837 sa->headrct.ymin= sa->headrct.ymax-HEADERY;
1838 sa->winrct.ymax= sa->headrct.ymin-1;
1842 sa->headrct.ymax= sa->headrct.ymin;
1844 if(sa->winrct.ymin>sa->winrct.ymax) sa->winrct.ymin= sa->winrct.ymax;
1847 sa->winx= sa->winrct.xmax-sa->winrct.xmin+1;
1848 sa->winy= sa->winrct.ymax-sa->winrct.ymin+1;
1851 static void openheadwin(ScrArea *sa)
1853 sa->headwin= myswinopen(G.curscreen->mainwin,
1854 sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1856 glMatrixMode(GL_MODELVIEW);
1858 areawinar[sa->headwin]= sa; /* otherwise addqueue does not work */
1860 scrarea_do_headchange(sa); /* headchange is no callback, apply right away. this is for render-to-imagewindow... this can be called on startup by sequencer, which invokes redraw before all events are handled. bad stuff... */
1861 addqueue(sa->headwin, CHANGED, 1);
1864 static void openareawin(ScrArea *sa)
1866 sa->win= myswinopen(G.curscreen->mainwin,
1867 sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1869 areawinar[sa->win]= sa; /* otherwise addqueue does not work */
1870 addqueue(sa->win, CHANGED, 1);
1873 static void closeheadwin(ScrArea *sa)
1875 if(sa->headwin) mywinclose(sa->headwin);
1879 static void closeareawin(ScrArea *sa)
1881 uiFreeBlocksWin(&sa->uiblocks, sa->win);
1883 if(sa->win) mywinclose(sa->win);
1887 static void del_area(ScrArea *sa)
1894 uiFreeBlocks(&sa->uiblocks);
1895 uiFreePanels(&sa->panels);
1896 #ifndef DISABLE_PYTHON
1897 BPY_free_scriptlink(&sa->scriptlink);
1899 if(sa==curarea) curarea= NULL;
1900 if(sa==g_activearea) g_activearea= NULL;
1903 /* sa2 to sa1, we swap spaces for fullscreen to keep all allocated data */
1904 static void copy_areadata(ScrArea *sa1, ScrArea *sa2, int swap_space)
1906 Panel *pa1, *pa2, *patab;
1907 ScriptLink *slink1 = &sa1->scriptlink, *slink2 = &sa2->scriptlink;
1909 sa1->headertype= sa2->headertype;
1910 sa1->spacetype= sa2->spacetype;
1911 Mat4CpyMat4(sa1->winmat, sa2->winmat);
1914 SWAP(ListBase, sa1->spacedata, sa2->spacedata);
1915 /* exception: ensure preview is reset */
1916 if(sa1->spacetype==SPACE_VIEW3D)
1917 BIF_view3d_previewrender_free(sa1->spacedata.first);
1921 duplicatespacelist(sa1, &sa1->spacedata, &sa2->spacedata);
1924 BLI_freelistN(&sa1->panels);
1925 duplicatelist(&sa1->panels, &sa2->panels);
1927 /* space handler script links */
1928 if (slink1->totscript) {
1929 MEM_freeN(slink1->scripts);
1930 MEM_freeN(slink1->flag);
1931 slink1->totscript = 0;
1933 if (slink2->totscript) {
1934 slink1->scripts = MEM_dupallocN(slink2->scripts);
1935 slink1->flag = MEM_dupallocN(slink2->flag);
1936 slink1->totscript = slink2->totscript;
1940 pa1= sa1->panels.first;
1943 patab= sa1->panels.first;
1944 pa2= sa2->panels.first;
1946 if( pa1->paneltab == pa2) {
1947 pa1->paneltab = patab;
1957 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
1959 ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
1960 sa->cursor= CURSOR_STD;
1965 sa->headertype= headertype;
1966 sa->spacetype= spacetype;
1970 if (sa->headertype) openheadwin(sa);
1973 BLI_addtail(&sc->areabase, sa);
1977 static int rcti_eq(rcti *a, rcti *b) {
1978 return ((a->xmin==b->xmin && a->xmax==b->xmax) &&
1979 (a->ymin==b->ymin && a->ymax==b->ymax));
1982 static void testareas(void)
1986 /* test for header, if removed, or moved */
1987 /* test for window, if removed, or moved */
1989 for(sa= G.curscreen->areabase.first; sa; sa= next) {
1990 rcti oldhr= sa->headrct;
1991 rcti oldwr= sa->winrct;
1997 /* ilegally scaled down area.... */
1998 if(sa->totrct.xmin>=sa->totrct.xmax || sa->totrct.ymin>=sa->totrct.ymax) {
2000 BLI_remlink(&G.curscreen->areabase, sa);
2002 printf("Warning, removed zero sized window from screen %s\n", G.curscreen->id.name+2);
2007 if (!rcti_eq(&oldhr, &sa->headrct)) {
2008 mywinposition(sa->headwin, sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
2009 addqueue(sa->headwin, CHANGED, 1);
2012 if(sa->headbutlen<sa->winx) {
2014 addqueue(sa->headwin, CHANGED, 1);
2016 else if(sa->headbutofs+sa->winx > sa->headbutlen) {
2017 sa->headbutofs= sa->headbutlen-sa->winx;
2018 addqueue(sa->headwin, CHANGED, 1);
2022 if (!rcti_eq(&oldwr, &sa->winrct)) {
2023 SpaceLink *sl= sa->spacedata.first;
2025 mywinposition(sa->win, sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
2026 addqueue(sa->win, CHANGED, 1);
2028 /* exception handling... probably we need generic event */
2029 for(; sl; sl= sl->next)
2030 if(sl->spacetype==SPACE_VIEW3D)
2031 BIF_view3d_previewrender_free((View3D *)sl);
2036 /* remake global windowarray */
2037 memset(areawinar, 0, sizeof(void *)*MAXWIN);
2038 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
2039 areawinar[sa->headwin]= sa;
2040 areawinar[sa->win]= sa;
2043 /* test if winakt is OK */
2044 if( areawinar[G.curscreen->winakt]==0) G.curscreen->winakt= 0;
2047 static ScrArea *test_edge_area(ScrArea *sa, ScrEdge *se)
2049 /* test if edge is in area, if not,
2050 then find an area that has it */
2052 ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
2055 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
2056 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
2057 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
2058 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
2060 if(se1!=se && se2!=se && se3!=se && se4!=se) {
2062 sa= G.curscreen->areabase.first;
2064 /* a bit optimise? */
2065 if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
2066 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
2067 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
2068 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
2069 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
2070 if(se1==se || se2==se || se3==se || se4==se) return sa;
2076 return sa; /* is null when not find */
2079 ScrArea *closest_bigger_area(void)
2081 ScrArea *sa, *big=0;
2082 float cent[3], vec[3],len, len1, len2, len3, dist=1000;
2085 getmouseco_sc(mval);
2091 sa= G.curscreen->areabase.first;
2094 if(sa->winy>=curarea->winy) {
2096 /* mimimum of the 4 corners */
2097 vec[0]= sa->v1->vec.x; vec[1]= sa->v1->vec.y;
2098 len= VecLenf(vec, cent);
2099 vec[0]= sa->v2->vec.x; vec[1]= sa->v2->vec.y;
2100 len1= VecLenf(vec, cent);
2101 vec[0]= sa->v3->vec.x; vec[1]= sa->v3->vec.y;
2102 len2= VecLenf(vec, cent);
2103 vec[0]= sa->v4->vec.x; vec[1]= sa->v4->vec.y;
2104 len3= VecLenf(vec, cent);
2106 len= MIN4(len, len1, len2, len3);
2109 vec[0]= (sa->v2->vec.x+sa->v3->vec.x)/2;
2110 vec[1]= (sa->v1->vec.y+sa->v2->vec.y)/2;
2112 len+= 0.5*VecLenf(vec, cent);
2115 len-= sa->winy+sa->winx;
2127 else return curarea;
2130 /* ************ SCREEN MANAGEMENT ************** */
2132 static int statechanged= 0;
2133 void BIF_wait_for_statechange(void)
2135 if (!statechanged) {
2136 /* Safety, don't wait more than 0.1 seconds */
2137 double stime= PIL_check_seconds_timer();
2138 while (!statechanged) {
2139 winlay_process_events(1);
2140 if ((PIL_check_seconds_timer()-stime)>0.1) break;
2144 else PIL_sleep_ms(3); /* statechanged can be set '1' while holding mousebutton, causing locks */
2147 void getmouse(short *mval)
2149 winlay_process_events(0);
2150 window_get_mouse(mainwin, mval);
2152 short get_qual(void)
2154 winlay_process_events(0);
2155 return window_get_qual(mainwin);
2157 short get_mbut(void)
2159 winlay_process_events(0);
2160 return window_get_mbut(mainwin);
2163 /* return values of tablet data related functions are documented
2164 * in the Window struct, ghostwinlay.c */
2165 float get_pressure(void)
2167 winlay_process_events(0);
2168 return window_get_pressure(mainwin);
2170 void get_tilt(float *xtilt, float *ytilt)
2172 winlay_process_events(0);
2173 window_get_tilt(mainwin, xtilt, ytilt);
2175 short get_activedevice(void)
2177 winlay_process_events(0);
2178 return window_get_activedevice(mainwin);
2181 void getndof(float *sbval)
2183 winlay_process_events(0);
2184 window_get_ndof(mainwin, sbval);
2187 void filterNDOFvalues(float *sbval)
2193 if (fabs(sbval[i]) > max)
2194 max = fabs(sbval[i]);
2196 if (fabs(sbval[i]) != max )
2200 void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii)
2205 /* accept the extended ascii set (ton) */
2206 if( !val || ascii<32 ) {
2210 mainqenter_ext(evt, val, ascii);
2213 /* ScrVert ordering in a ScrArea:
2222 static bScreen *addscreen(char *name) /* use setprefsize() if you want something else than a full windpw */
2224 /* this function sets variabele G.curscreen,
2225 * that global is about used everywhere!
2228 ScrVert *sv1, *sv2, *sv3, *sv4;
2229 short startx, starty, endx, endy;
2231 sc= G.curscreen= alloc_libblock(&G.main->screen, ID_SCR, name);
2237 winlay_get_screensize(&prefsizx, &prefsizy);
2242 endx= prefstax+prefsizx-1;
2243 endy= prefstay+prefsizy-1;
2245 sc->startx= startx; sc->starty= starty;
2246 sc->endx= endx; sc->endy= endy;
2247 sc->sizex= sc->endx-sc->startx+1;
2248 sc->sizey= sc->endy-sc->starty+1;
2253 if (G.windowstate == G_WINDOWSTATE_FULLSCREEN)
2254 mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, G_WINDOWSTATE_FULLSCREEN);
2256 mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
2259 printf("ERROR: Unable to open Blender window\n");
2263 window_set_handler(mainwin, add_to_mainqueue, NULL);
2264 window_open_ndof(mainwin); /* needs to occur once the mainwin handler is set */
2268 /* for visual speed, but still needed? */
2269 glClearColor(.55, .55, .55, 0.0);
2270 glClear(GL_COLOR_BUFFER_BIT);
2271 window_swap_buffers(mainwin);
2273 /* this is unneeded and with large monitors can be a
2274 * pain so commenting out */
2275 /* warp_pointer(sc->sizex/2, sc->sizey/2); */
2277 mainqenter(REDRAW, 1);
2282 sv1= screen_addvert(sc, 0, 0);
2283 sv2= screen_addvert(sc, 0, sc->endy-sc->starty);
2284 sv3= screen_addvert(sc, sc->sizex-1, sc->sizey-1);
2285 sv4= screen_addvert(sc, sc->sizex-1, 0);
2287 screen_addedge(sc, sv1, sv2);
2288 screen_addedge(sc, sv2, sv3);
2289 screen_addedge(sc, sv3, sv4);
2290 screen_addedge(sc, sv4, sv1);
2292 screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_INFO);
2299 void setscreen(bScreen *sc)
2305 if(sc->full) { /* find associated full */
2306 sc1= G.main->screen.first;
2308 sa= sc1->areabase.first;
2315 if(sc1==0) printf("setscreen error\n");
2318 /* de-activate G.curscreen */
2319 if (G.curscreen && G.curscreen != sc) {
2320 sa= G.curscreen->areabase.first;
2322 if(sa->win) mywinclose(sa->win);
2324 if(sa->headwin) mywinclose(sa->headwin);
2327 uiFreeBlocks(&sa->uiblocks);
2332 else if(G.curscreen) markdirty_all(); /* at least redraw */
2334 if (G.curscreen != sc) {
2335 mywinset(sc->mainwin);
2340 for (sa= sc->areabase.first; sa; sa= sa->next) {
2342 /* if (sa->win || sa->headwin) */
2343 /* printf("error in setscreen (win): %d, %d\n", sa->win, sa->headwin); */
2346 if (!sa->headwin && sa->headertype)
2350 /* recalculate winakt */
2351 getmouseco_sc(mval);
2353 test_scale_screen(sc);
2356 for(sa= sc->areabase.first; sa; sa= sa->next) {
2359 for(sl= sa->spacedata.first; sl; sl= sl->next) {
2362 if(sl->spacetype==SPACE_OOPS) {
2363 SpaceOops *soops= (SpaceOops *) sl;
2365 /* patch for old files */
2366 if(soops->v2d.cur.xmin==soops->v2d.cur.xmax) {
2367 init_v2d_oops(sa, soops);
2370 else if(sl->spacetype==SPACE_BUTS) {
2371 SpaceButs *sbuts= (SpaceButs *)sl;
2372 sbuts->re_align= 1; // force an align call, maybe new panels were added, also for after file reading
2376 sa->cursor= CURSOR_STD;
2379 if(G.scene!=sc->scene)
2380 set_scene(sc->scene);
2384 G.curscreen->winakt= 0;
2385 curarea= sc->areabase.first;
2387 mainqenter(DRAWEDGES, 1);
2388 dodrawscreen= 1; /* patch! even gets lost,,,? */
2390 winqueue_break= 1; /* means leave queue everywhere */
2393 static void splitarea(ScrArea *sa, char dir, float fac);
2395 void area_fullscreen(void) /* with curarea */
2397 /* this function toggles: if area is full then the parent will be restored */
2398 bScreen *sc, *oldscreen;
2399 ScrArea *sa, *newa, *old;
2400 short headertype, fulltype;
2403 sc= curarea->full; /* the old screen */
2404 fulltype = sc->full;
2406 // refuse to go out of SCREENAUTOPLAY as long as G_FLAGS_AUTOPLAY
2409 if (fulltype != SCREENAUTOPLAY || (G.flags & G_FILE_AUTOPLAY) == 0) {
2413 old= sc->areabase.first;
2415 if(old->full) break;
2418 if(old==0) {error("something wrong in areafullscreen"); return;}
2420 if (fulltype == SCREENAUTOPLAY) {
2421 // in autoplay screens the headers are disabled by
2422 // default. So use the old headertype instead
2423 headertype = old->headertype;
2425 // normal fullscreen. Use current headertype
2426 headertype = curarea->headertype;
2429 copy_areadata(old, curarea, 1); /* 1 = swap spacelist */
2430 old->headertype = headertype;
2434 unlink_screen(G.curscreen);
2435 free_libblock(&G.main->screen, G.curscreen);
2443 /* is there only 1 area? */
2444 if(G.curscreen->areabase.first==G.curscreen->areabase.last) return;
2445 if(curarea->spacetype==SPACE_INFO) return;
2447 G.curscreen->full = SCREENFULL;
2450 oldscreen= G.curscreen;
2451 sc= addscreen("temp"); /* this sets G.curscreen */
2453 splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
2454 newa= sc->areabase.first;
2455 newspace(newa->next, SPACE_INFO);
2458 G.curscreen= oldscreen; /* needed because of setscreen */
2461 copy_areadata(newa, curarea, 1); /* 1 = swap spacelist */
2463 curarea->full= oldscreen;
2464 newa->full= oldscreen;
2465 newa->next->full= oldscreen;
2471 /* there's also events in queue for this, but we call fullscreen for render output
2472 now, and that doesn't go back to queue. Bad code, but doesn't hurt... (ton) */
2473 for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
2474 scrarea_do_headchange(sa);
2475 scrarea_do_winchange(sa);
2477 /* bad code #2: setscreen() ends with first area active. fullscreen render assumes this too */
2478 curarea= sc->areabase.first;
2480 retopo_force_update();
2483 static void area_autoplayscreen(void)
2485 bScreen *sc, *oldscreen;
2486 ScrArea *newa, *old, *sa;
2488 if (curarea->full) {
2492 if (curarea->full == NULL) {
2493 sa = G.curscreen->areabase.first;
2495 if (sa->spacetype == SPACE_VIEW3D) {
2502 areawinset(sa->win);
2503 G.curscreen->full = SCREENAUTOPLAY;
2506 oldscreen= G.curscreen;
2507 sc= addscreen("temp"); /* this sets G.curscreen */
2509 newa= sc->areabase.first;
2512 G.curscreen= oldscreen; /* because of setscreen */
2514 /* copy area settings */
2515 copy_areadata(newa, curarea, 1); /* swap spacedata */
2516 newa->headertype= 0;
2518 curarea->full= oldscreen;
2519 newa->full= oldscreen;
2527 static void copy_screen(bScreen *to, bScreen *from)
2535 winqueue_break= 1; /* leave queues everywhere */
2537 duplicatelist(&to->vertbase, &from->vertbase);
2538 duplicatelist(&to->edgebase, &from->edgebase);
2539 duplicatelist(&to->areabase, &from->areabase);
2541 s1= from->vertbase.first;
2542 s2= to->vertbase.first;
2548 se= to->edgebase.first;
2550 se->v1= se->v1->newv;
2551 se->v2= se->v2->newv;
2552 sortscrvert(&(se->v1), &(se->v2));
2556 sa= to->areabase.first;
2557 saf= from->areabase.first;
2559 sa->v1= sa->v1->newv;
2560 sa->v2= sa->v2->newv;
2561 sa->v3= sa->v3->newv;
2562 sa->v4= sa->v4->newv;
2566 sa->spacedata.first= sa->spacedata.last= NULL;
2567 sa->uiblocks.first= sa->uiblocks.last= NULL;
2568 sa->panels.first= sa->panels.last= NULL;
2569 sa->scriptlink.totscript= 0;
2571 copy_areadata(sa, saf, 0);
2577 /* put at zero (needed?) */
2578 s1= from->vertbase.first;
2585 void duplicate_screen(void)
2587 bScreen *sc, *oldscreen;
2589 if(G.curscreen->full != SCREENNORMAL) return;
2591 /* make new screen: */
2593 oldscreen= G.curscreen;
2594 sc= addscreen(oldscreen->id.name+2); /* this sets G.curscreen */
2595 copy_screen(sc, oldscreen);
2597 G.curscreen= oldscreen;
2603 /* ************ END SCREEN MANAGEMENT ************** */
2604 /* ************ JOIN/SPLIT/MOVE ************** */
2606 typedef struct point{
2610 /* draw vertical shape visualising future joining (left as well
2611 * right direction of future joining) */
2612 static void draw_horizontal_join_shape(ScrArea *sa, char dir)
2617 float width = sa->v3->vec.x - sa->v1->vec.x;
2618 float height = sa->v3->vec.y - sa->v1->vec.y;
2629 points[0].x = sa->v1->vec.x;
2630 points[0].y = sa->v1->vec.y + height/2;
2632 points[1].x = sa->v1->vec.x;
2633 points[1].y = sa->v1->vec.y;
2635 points[2].x = sa->v4->vec.x - w;
2636 points[2].y = sa->v4->vec.y;
2638 points[3].x = sa->v4->vec.x - w;
2639 points[3].y = sa->v4->vec.y + height/2 - 2*h;
2641 points[4].x = sa->v4->vec.x - 2*w;
2642 points[4].y = sa->v4->vec.y + height/2;
2644 points[5].x = sa->v4->vec.x - w;
2645 points[5].y = sa->v4->vec.y + height/2 + 2*h;
2647 points[6].x = sa->v3->vec.x - w;
2648 points[6].y = sa->v3->vec.y;
2650 points[7].x = sa->v2->vec.x;
2651 points[7].y = sa->v2->vec.y;
2653 points[8].x = sa->v4->vec.x;
2654 points[8].y = sa->v4->vec.y + height/2 - h;
2656 points[9].x = sa->v4->vec.x;
2657 points[9].y = sa->v4->vec.y + height/2 + h;
2660 /* when direction is left, then we flip direction of arrow */
2661 float cx = sa->v1->vec.x + width;
2664 points[i].x = -points[i].x;
2665 points[i].x += sa->v1->vec.x;
2669 glBegin(GL_POLYGON);
2671 glVertex2f(points[i].x, points[i].y);
2673 glBegin(GL_POLYGON);
2675 glVertex2f(points[i].x, points[i].y);
2676 glVertex2f(points[0].x, points[0].y);
2679 glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
2680 glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
2683 /* draw vertical shape visualising future joining (up/down direction) */
2684 static void draw_vertical_join_shape(ScrArea *sa, char dir)
2689 float width = sa->v3->vec.x - sa->v1->vec.x;
2690 float height = sa->v3->vec.y - sa->v1->vec.y;
2701 points[0].x = sa->v1->vec.x + width/2;
2702 points[0].y = sa->v3->vec.y;
2704 points[1].x = sa->v2->vec.x;
2705 points[1].y = sa->v2->vec.y;
2707 points[2].x = sa->v1->vec.x;
2708 points[2].y = sa->v1->vec.y + h;
2710 points[3].x = sa->v1->vec.x + width/2 - 2*w;
2711 points[3].y = sa->v1->vec.y + h;
2713 points[4].x = sa->v1->vec.x + width/2;
2714 points[4].y = sa->v1->vec.y + 2*h;
2716 points[5].x = sa->v1->vec.x + width/2 + 2*w;
2717 points[5].y = sa->v1->vec.y + h;
2719 points[6].x = sa->v4->vec.x;
2720 points[6].y = sa->v4->vec.y + h;
2722 points[7].x = sa->v3->vec.x;
2723 points[7].y = sa->v3->vec.y;
2725 points[8].x = sa->v1->vec.x + width/2 - w;
2726 points[8].y = sa->v1->vec.y;
2728 points[9].x = sa->v1->vec.x + width/2 + w;
2729 points[9].y = sa->v1->vec.y;
2732 /* when direction is up, then we flip direction of arrow */
2733 float cy = sa->v1->vec.y + height;
2736 points[i].y = -points[i].y;
2737 points[i].y += sa->v1->vec.y;
2741 glBegin(GL_POLYGON);
2743 glVertex2f(points[i].x, points[i].y);
2745 glBegin(GL_POLYGON);
2747 glVertex2f(points[i].x, points[i].y);
2748 glVertex2f(points[0].x, points[0].y);
2751 glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
2752 glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
2755 /* draw join shape due to direction of joining */
2756 static void draw_join_shape(ScrArea *sa, char dir)
2758 if(dir=='u' || dir=='d')
2759 draw_vertical_join_shape(sa, dir);
2761 draw_horizontal_join_shape(sa, dir);
2764 /* draw screen area darker with arrow (visualisation of future joining) */
2765 static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
2767 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2769 glColor4ub(0, 0, 0, 105);
2770 draw_join_shape(sa, dir);
2771 glDisable(GL_BLEND);
2774 /* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
2775 static void scrarea_draw_shape_light(ScrArea *sa, char dir)
2777 glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
2779 /* value 181 was hardly computed: 181~105 */
2780 glColor4ub(255, 255, 255, 181);
2781 draw_join_shape(sa, dir);
2782 glDisable(GL_BLEND);
2785 static void joinarea_interactive(ScrArea *area, ScrEdge *onedge)
2787 struct ScrArea *sa1 = area, *sa2, *scr;
2788 struct ScrArea *up=0, *down=0, *right=0, *left=0;
2790 unsigned short event;
2791 short ok=0, val=0, mval[2];
2794 sa1 = test_edge_area(sa1, onedge);
2797 /* find directions with same edge */
2798 sa2= G.curscreen->areabase.first;
2801 se= screen_findedge(G.curscreen, sa2->v1, sa2->v2);
2802 if(onedge==se) right= sa2;
2803 se= screen_findedge(G.curscreen, sa2->v2, sa2->v3);
2804 if(onedge==se) down= sa2;
2805 se= screen_findedge(G.curscreen, sa2->v3, sa2->v4);
2806 if(onedge==se) left= sa2;
2807 se= screen_findedge(G.curscreen, sa2->v4, sa2->v1);
2808 if(onedge==se) up= sa2;
2842 mywinset(G.curscreen->mainwin);
2844 /* initial set up screen area asigned for destroying */
2847 /* set up standard cursor */
2848 set_cursor(CURSOR_STD);
2850 /* should already have a good matrix */
2851 glReadBuffer(GL_FRONT);
2852 glDrawBuffer(GL_FRONT);
2854 /* to prevent flickering after clicking at "Join Areas " */
2855 getmouseco_sc(mval);
2857 if(scr==left && mval[0]>=onedge->v1->vec.x) scr = right;
2858 else if(scr==right && mval[0]<onedge->v1->vec.x) scr = left;
2861 if(scr==down && mval[1]>=onedge->v1->vec.y) scr = up;
2862 else if(scr==up && mval[1]<onedge->v1->vec.y) scr = down;
2865 /* draw scr screen area with dark shape */
2867 scrarea_draw_shape_dark(scr,'r');
2869 scrarea_draw_shape_dark(scr,'l');
2871 scrarea_draw_shape_dark(scr,'d');
2873 scrarea_draw_shape_dark(scr,'u');
2876 /* "never ending loop" of interactive selection */
2878 getmouseco_sc(mval);
2880 /* test if position of mouse is on the "different side" of
2883 if(scr==left && mval[0]>=onedge->v1->vec.x) {
2884 scrarea_draw_shape_light(scr,'r');
2886 scrarea_draw_shape_dark(scr,'l');
2888 else if(scr==right && mval[0]<onedge->v1->vec.x) {
2889 scrarea_draw_shape_light(scr,'l');
2891 scrarea_draw_shape_dark(scr,'r');
2895 if(scr==down && mval[1]>=onedge->v1->vec.y) {
2896 scrarea_draw_shape_light(scr,'u');
2898 scrarea_draw_shape_dark(scr,'d');
2900 else if(scr==up && mval[1]<onedge->v1->vec.y){
2901 scrarea_draw_shape_light(scr,'d');
2903 scrarea_draw_shape_dark(scr,'u');
2908 /* get pressed keys and mouse buttons */
2909 event = extern_qread(&val);
2911 /* confirm joining of two screen areas */
2912 if(val && event==LEFTMOUSE) ok= 1;
2914 /* cancel joining of joining */
2915 if(val && (event==ESCKEY || event==RIGHTMOUSE)) ok= -1;
2920 glReadBuffer(GL_BACK);
2921 glDrawBuffer(GL_BACK);
2923 /* joining af screen areas was confirmed ... proceed joining */
2933 screen_addedge(G.curscreen, sa1->v2, sa1->v3);
2934 screen_addedge(G.curscreen, sa1->v1, sa1->v4);
2939 screen_addedge(G.curscreen, sa1->v1, sa1->v2);
2940 screen_addedge(G.curscreen, sa1->v3, sa1->v4);
2942 else if(sa2==right) {
2945 screen_addedge(G.curscreen, sa1->v2, sa1->v3);
2946 screen_addedge(G.curscreen, sa1->v1, sa1->v4);
2948 else if(sa2==down) {
2951 screen_addedge(G.curscreen, sa1->v1, sa1->v2);
2952 screen_addedge(G.curscreen, sa1->v3, sa1->v4);
2956 BLI_remlink(&G.curscreen->areabase, sa2);
2959 removedouble_scredges();
2960 removenotused_scredges();
2961 removenotused_scrverts();
2964 mainqenter(DRAWEDGES, 1);
2966 /* test cursor en inputwindow */
2967 mainqenter(MOUSEY, -1);
2971 static short testsplitpoint(ScrArea *sa, char dir, float fac)
2972 /* return 0: no split possible */
2973 /* else return (integer) screencoordinate split point */
2977 /* area big enough? */
2978 if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
2979 if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
2982 if(fac<0.0) fac= 0.0;
2983 if(fac>1.0) fac= 1.0;
2986 y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
2988 if(sa->v2->vec.y==G.curscreen->sizey-1 && sa->v2->vec.y- y < HEADERY)
2989 y= sa->v2->vec.y- HEADERY;
2991 else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY)
2992 y= sa->v1->vec.y+ HEADERY;
2994 else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
2995 else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
2996 else y-= (y % AREAGRID);
3001 x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
3002 if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
3003 else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
3004 else x-= (x % AREAGRID);
3010 static void splitarea(ScrArea *sa, char dir, float fac)
3019 split= testsplitpoint(sa, dir, fac);
3020 if(split==0) return;
3024 areawinset(sa->win);
3028 sv1= screen_addvert(sc, sa->v1->vec.x, split);
3029 sv2= screen_addvert(sc, sa->v4->vec.x, split);
3032 screen_addedge(sc, sa->v1, sv1);
3033 screen_addedge(sc, sv1, sa->v2);
3034 screen_addedge(sc, sa->v3, sv2);
3035 screen_addedge(sc, sv2, sa->v4);
3036 screen_addedge(sc, sv1, sv2);
3038 /* new areas: top */
3039 newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
3040 copy_areadata(newa, sa, 0);
3049 sv1= screen_addvert(sc, split, sa->v1->vec.y);
3050 sv2= screen_addvert(sc, split, sa->v2->vec.y);
3053 screen_addedge(sc, sa->v1, sv1);
3054 screen_addedge(sc, sv1, sa->v4);
3055 screen_addedge(sc, sa->v2, sv2);
3056 screen_addedge(sc, sv2, sa->v3);
3057 screen_addedge(sc, sv1, sv2);
3059 /* new areas: left */
3060 newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
3061 copy_areadata(newa, sa, 0);
3068 if(sa->spacetype==SPACE_BUTS) {
3069 addqueue(sa->win, UI_BUT_EVENT, B_BUTSHOME);
3070 addqueue(newa->win, UI_BUT_EVENT, B_BUTSHOME);
3073 /* remove double vertices en edges */
3074 removedouble_scrverts();
3075 removedouble_scredges();
3076 removenotused_scredges();
3078 mainqenter(DRAWEDGES, 1);
3079 dodrawscreen= 1; /* patch! event gets lost,,,? */
3083 static void scrarea_draw_splitpoint(ScrArea *sa, char dir, float fac)
3085 int split= testsplitpoint(sa, dir, fac);
3089 sdrawXORline(sa->totrct.xmin, split, sa->totrct.xmax, split);
3090 sdrawXORline(sa->totrct.xmin, split-1, sa->totrct.xmax, split-1);
3092 sdrawXORline(split, sa->totrct.ymin, split, sa->totrct.ymax);
3093 sdrawXORline(split-1, sa->totrct.ymin, split-1, sa->totrct.ymax);
3098 static void splitarea_interactive(ScrArea *area, ScrEdge *onedge)
3100 ScrArea *scr, *sa= area;
3102 unsigned short event;
3103 short ok= 0, val, split = 0, mval[2], mvalo[2]= {-1, -1}, first= 1;
3106 if(sa->win==0) return;
3107 if(sa->full) return;
3108 if(myswinopen_allowed()==0) {
3109 error("Max amount of subwindows reached");
3113 dir= scredge_is_horizontal(onedge)?'v':'h';
3115 mywinset(G.curscreen->mainwin);
3116 /* should already have a good matrix */
3117 glReadBuffer(GL_FRONT);
3118 glDrawBuffer(GL_FRONT);
3120 /* keep track of grid and minsize */
3122 getmouseco_sc(mval);
3124 /* this part of code allows to choose, what window will be splited */
3125 /* cursor is out of the current ScreenArea */
3126 if((mval[0] < sa->v1->vec.x) || (mval[0] > sa->v3->vec.x) ||
3127 (mval[1] < sa->v1->vec.y) || (mval[1] > sa->v3->vec.y)){
3128 scr= (ScrArea*)G.curscreen->areabase.first;
3130 if((mval[0] > scr->v1->vec.x) && (mval[0] < scr->v4->vec.x) &&
3131 (mval[1] < scr->v2->vec.y) && (mval[1] > scr->v1->vec.y)){
3132 /* test: is ScreenArea enough big for splitting */
3133 short tsplit= testsplitpoint(scr, dir, fac);
3136 /* delete old line from previous ScreenArea */
3137 if(!first) scrarea_draw_splitpoint(sa, dir, fac);
3147 if (first || (dir=='v' && mval[0]!=mvalo[0]) || (dir=='h' && mval[1]!=mvalo[1])) {
3149 scrarea_draw_splitpoint(sa, dir, fac);
3153 fac= mval[1]- (sa->v1->vec.y);
3154 fac/= sa->v2->vec.y- sa->v1->vec.y;
3156 fac= mval[0]- sa->v1->vec.x;
3157 fac/= sa->v4->vec.x- sa->v1->vec.x;
3160 split= testsplitpoint(sa, dir, fac);
3162 scrarea_draw_splitpoint(sa, dir, fac);
3172 event= extern_qread(&val);
3174 /* change direction of splitting between horizontal and vertical
3175 * patch was offered by Guillaume */
3176 if(val && (event==TABKEY || event==MIDDLEMOUSE)) {
3177 scrarea_draw_splitpoint(sa, dir, fac);
3180 set_cursor(CURSOR_Y_MOVE);
3183 set_cursor(CURSOR_X_MOVE);
3188 if(val && event==LEFTMOUSE) {
3190 fac= split- (sa->v1->vec.y);
3191 fac/= sa->v2->vec.y- sa->v1->vec.y;
3194 fac= split- sa->v1->vec.x;
3195 fac/= sa->v4->vec.x- sa->v1->vec.x;
3199 if(val && (event==ESCKEY || event==RIGHTMOUSE)) {
3206 scrarea_draw_splitpoint(sa, dir, fac);
3209 glReadBuffer(GL_BACK);
3210 glDrawBuffer(GL_BACK);
3213 splitarea(sa, dir, fac);
3214 mainqenter(DRAWEDGES, 1);
3215 dodrawscreen= 1; /* patch! event gets lost,,,? */
3219 View3D *find_biggest_view3d(void)
3221 ScrArea *sa= find_biggest_area_of_type(SPACE_VIEW3D);
3224 return (View3D*) sa->spacedata.first;
3230 ScrArea *find_biggest_area_of_type(int spacecode)
3232 ScrArea *sa, *biggest= NULL;
3235 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
3236 if (spacecode==0 || sa->spacetype==spacecode) {
3237 int x= sa->v3->vec.x - sa->v1->vec.x;
3238 int y= sa->v3->vec.y - sa->v1->vec.y;
3239 int size= x*x + y*y;
3241 if (!biggest || size>bigsize) {
3251 ScrArea *find_biggest_area(void)
3253 return find_biggest_area_of_type(0);
3256 static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
3263 /* select connected, only in the right direction */
3264 /* 'dir' is the direction of EDGE */
3266 if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';