Converted the Userpreference buttons to zr's new ButBit calls.
[blender.git] / source / blender / src / ghostwinlay.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32 #include <stdlib.h>
33 #include <stdio.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifdef WIN32
40 #include "BLI_winstuff.h"
41 #endif
42
43 #include "MEM_guardedalloc.h"
44
45 #include "DNA_listBase.h"       
46 #include "DNA_userdef_types.h"  /* U.flag & TWOBUTTONMOUSE */
47
48 #include "BLI_blenlib.h"
49
50 #include "GHOST_C-api.h"
51
52 #include "BKE_utildefines.h"
53 #include "BKE_global.h"
54
55 #include "BIF_gl.h"
56 #include "BIF_graphics.h"
57 #include "BIF_mywindow.h"
58 #include "BIF_screen.h"
59 #include "BIF_usiblender.h"
60
61 #include "mydevice.h"
62 #include "blendef.h"
63
64 #include "winlay.h"
65
66 static GHOST_SystemHandle g_system= 0;
67
68         /* Some simple ghost <-> blender conversions */
69         
70 static GHOST_TStandardCursor convert_cursor(int curs) {
71         switch(curs) {
72         default:
73         case CURSOR_STD:                return GHOST_kStandardCursorDefault;
74         case CURSOR_VPAINT:             return GHOST_kStandardCursorRightArrow;
75         case CURSOR_FACESEL:            return GHOST_kStandardCursorRightArrow;
76         case CURSOR_WAIT:               return GHOST_kStandardCursorWait;
77         case CURSOR_EDIT:               return GHOST_kStandardCursorCrosshair;
78         case CURSOR_HELP:               return GHOST_kStandardCursorHelp;
79         case CURSOR_X_MOVE:             return GHOST_kStandardCursorLeftRight;
80         case CURSOR_Y_MOVE:             return GHOST_kStandardCursorUpDown;
81         case CURSOR_PENCIL:             return GHOST_kStandardCursorPencil;
82         }
83 }
84
85 static int convert_mbut(GHOST_TButtonMask but) {
86         if (but == GHOST_kButtonMaskLeft) {
87                 return LEFTMOUSE;
88         } else if (but == GHOST_kButtonMaskRight) {
89                 return RIGHTMOUSE;
90         } else {
91                 return MIDDLEMOUSE;
92         }
93 }
94
95 static int convert_key(GHOST_TKey key) {
96         if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
97                 return (AKEY + ((int) key - GHOST_kKeyA));
98         } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
99                 return (ZEROKEY + ((int) key - GHOST_kKey0));
100         } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
101                 return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
102         } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
103                 return (F1KEY + ((int) key - GHOST_kKeyF1));
104         } else {
105                 switch (key) {
106                 case GHOST_kKeyBackSpace:               return BACKSPACEKEY;
107                 case GHOST_kKeyTab:                             return TABKEY;
108                 case GHOST_kKeyLinefeed:                return LINEFEEDKEY;
109                 case GHOST_kKeyClear:                   return 0;
110                 case GHOST_kKeyEnter:                   return RETKEY;
111         
112                 case GHOST_kKeyEsc:                             return ESCKEY;
113                 case GHOST_kKeySpace:                   return SPACEKEY;
114                 case GHOST_kKeyQuote:                   return QUOTEKEY;
115                 case GHOST_kKeyComma:                   return COMMAKEY;
116                 case GHOST_kKeyMinus:                   return MINUSKEY;
117                 case GHOST_kKeyPeriod:                  return PERIODKEY;
118                 case GHOST_kKeySlash:                   return SLASHKEY;
119
120                 case GHOST_kKeySemicolon:               return SEMICOLONKEY;
121                 case GHOST_kKeyEqual:                   return EQUALKEY;
122
123                 case GHOST_kKeyLeftBracket:             return LEFTBRACKETKEY;
124                 case GHOST_kKeyRightBracket:    return RIGHTBRACKETKEY;
125                 case GHOST_kKeyBackslash:               return BACKSLASHKEY;
126                 case GHOST_kKeyAccentGrave:             return ACCENTGRAVEKEY;
127
128                 case GHOST_kKeyLeftShift:               return LEFTSHIFTKEY;
129                 case GHOST_kKeyRightShift:              return RIGHTSHIFTKEY;
130                 case GHOST_kKeyLeftControl:             return LEFTCTRLKEY;
131                 case GHOST_kKeyRightControl:    return RIGHTCTRLKEY;
132                 case GHOST_kKeyLeftAlt:                 return LEFTALTKEY;
133                 case GHOST_kKeyRightAlt:                return RIGHTALTKEY;
134
135                 case GHOST_kKeyCapsLock:                return CAPSLOCKKEY;
136                 case GHOST_kKeyNumLock:                 return 0;
137                 case GHOST_kKeyScrollLock:              return 0;
138
139                 case GHOST_kKeyLeftArrow:               return LEFTARROWKEY;
140                 case GHOST_kKeyRightArrow:              return RIGHTARROWKEY;
141                 case GHOST_kKeyUpArrow:                 return UPARROWKEY;
142                 case GHOST_kKeyDownArrow:               return DOWNARROWKEY;
143
144                 case GHOST_kKeyPrintScreen:             return 0;
145                 case GHOST_kKeyPause:                   return PAUSEKEY;
146
147                 case GHOST_kKeyInsert:                  return INSERTKEY;
148                 case GHOST_kKeyDelete:                  return DELKEY;
149                 case GHOST_kKeyHome:                    return HOMEKEY;
150                 case GHOST_kKeyEnd:                             return ENDKEY;
151                 case GHOST_kKeyUpPage:                  return PAGEUPKEY;
152                 case GHOST_kKeyDownPage:                return PAGEDOWNKEY;
153
154                 case GHOST_kKeyNumpadPeriod:    return PADPERIOD;
155                 case GHOST_kKeyNumpadEnter:             return PADENTER;
156                 case GHOST_kKeyNumpadPlus:              return PADPLUSKEY;
157                 case GHOST_kKeyNumpadMinus:             return PADMINUS;
158                 case GHOST_kKeyNumpadAsterisk:  return PADASTERKEY;
159                 case GHOST_kKeyNumpadSlash:             return PADSLASHKEY;
160                 case GHOST_kKeyUnknown:                 return UNKNOWNKEY;
161
162                 default:
163                         return 0;
164                 }
165         }
166 }
167
168         /***/
169         
170
171 static Window *window_new(GHOST_WindowHandle ghostwin)
172 {
173         Window *win= MEM_callocN(sizeof(*win), "Window");
174         win->ghostwin= ghostwin;
175         
176         return win;
177 }
178
179 static void window_handle(Window *win, short event, short val)
180 {
181         if (win->handler) {
182                 win->handler(win, win->user_data, event, val, 0);
183         }
184 }
185
186 static void window_handle_ext(Window *win, short event, short val, short extra)
187 {
188         if (win->handler) {
189                 win->handler(win, win->user_data, event, val, extra);
190         }
191 }
192
193 static void window_free(Window *win) 
194 {
195         MEM_freeN(win);
196 }
197
198         /***/
199
200 static Window *active_gl_window= NULL;
201
202 Window *window_open(char *title, int posx, int posy, int sizex, int sizey, int start_maximized)
203 {
204         GHOST_WindowHandle ghostwin;
205         GHOST_TWindowState inital_state;
206         int scr_w, scr_h;
207
208         winlay_get_screensize(&scr_w, &scr_h);
209         if(G.f & G_DEBUG) {
210                 printf("screen size %d %d\n", scr_w, scr_h);    
211                 printf("win start %d %d size %d %d\n",  posx,  posy,  sizex,  sizey);
212         }
213         posy= (scr_h-posy-sizey);
214         
215         /* create a fullscreen window on unix by default*/
216 #if !defined(WIN32) && !defined(__APPLE__)
217         inital_state= start_maximized?
218                 GHOST_kWindowStateFullScreen:GHOST_kWindowStateNormal;
219 #else
220 #ifdef _WIN32   // FULLSCREEN
221         if (start_maximized == G_WINDOWSTATE_FULLSCREEN)
222                 inital_state= GHOST_kWindowStateFullScreen;
223         else
224                 inital_state= start_maximized?GHOST_kWindowStateMaximized:GHOST_kWindowStateNormal;
225 #else                   // APPLE
226         inital_state= start_maximized?GHOST_kWindowStateMaximized:GHOST_kWindowStateNormal;
227 #endif
228 #endif
229
230         ghostwin= GHOST_CreateWindow(g_system, 
231                                                                 title, 
232                                                                 posx, posy, sizex, sizey, 
233                                                                 inital_state, 
234                                                                 GHOST_kDrawingContextTypeOpenGL,
235                                                                 0 /* no stereo */);
236         
237         if (ghostwin) {
238                 Window *win= window_new(ghostwin);
239                 
240                 if (win) {
241                         GHOST_SetWindowUserData(ghostwin, win);
242                         
243                         win->position[0]= posx;
244                         win->position[1]= posy;
245                         win->size[0]= sizex;
246                         win->size[1]= sizey;
247                         
248                         win->lmouse[0]= win->size[0]/2;
249                         win->lmouse[1]= win->size[1]/2;
250                 } else {
251                         GHOST_DisposeWindow(g_system, ghostwin);
252                 }
253                 
254                 return win;
255         } else {
256                 return NULL;
257         }
258 }
259
260 void window_set_handler(Window *win, WindowHandlerFP handler, void *user_data)
261 {
262         win->handler= handler;
263         win->user_data= user_data;
264 }
265
266 static void window_timer_proc(GHOST_TimerTaskHandle timer, GHOST_TUns64 time)
267 {
268         Window *win= GHOST_GetTimerTaskUserData(timer);
269
270         win->handler(win, win->user_data, win->timer_event, 0, 0);
271 }
272
273 void window_set_timer(Window *win, int delay_ms, int event)
274 {
275         if (win->timer) GHOST_RemoveTimer(g_system, win->timer);
276
277         win->timer_event= event;
278         win->timer= GHOST_InstallTimer(g_system, delay_ms, delay_ms, window_timer_proc, win);
279 }
280
281 void window_destroy(Window *win) {
282         if (active_gl_window==win) {
283                 active_gl_window= NULL;
284         }
285         
286         if (win->timer) {
287                 GHOST_RemoveTimer(g_system, win->timer);
288                 win->timer= NULL;
289         }
290
291         GHOST_DisposeWindow(g_system, win->ghostwin);
292         window_free(win);
293 }
294
295 void window_set_cursor(Window *win, int curs) {
296         if (curs==CURSOR_NONE) {
297                 GHOST_SetCursorVisibility(win->ghostwin, 0);
298         } else {
299                 GHOST_SetCursorVisibility(win->ghostwin, 1);
300                 GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs));
301         }
302 }
303
304 void window_set_custom_cursor(Window *win, unsigned char mask[16][2], 
305                                         unsigned char bitmap[16][2], int hotx, int hoty) {
306         GHOST_SetCustomCursorShape(win->ghostwin, bitmap, mask, hotx, hoty);
307 }
308
309 void window_make_active(Window *win) {
310         if (win != active_gl_window) {
311                 active_gl_window= win;
312                 GHOST_ActivateWindowDrawingContext(win->ghostwin);
313         }
314 }
315
316 void window_swap_buffers(Window *win) {
317         GHOST_SwapWindowBuffers(win->ghostwin);
318 }
319
320 static int query_qual(char qual) {
321         GHOST_TModifierKeyMask left, right;
322         int val= 0;
323         
324         if (qual=='s') {
325                 left= GHOST_kModifierKeyLeftShift;
326                 right= GHOST_kModifierKeyRightShift;
327         } else if (qual=='c') {
328                 left= GHOST_kModifierKeyLeftControl;
329                 right= GHOST_kModifierKeyRightControl;
330         } else if (qual=='C') {
331                 left= right= GHOST_kModifierKeyCommand;
332         } else {
333                 left= GHOST_kModifierKeyLeftAlt;
334                 right= GHOST_kModifierKeyRightAlt;
335         }
336
337         GHOST_GetModifierKeyState(g_system, left, &val);
338         if (!val)
339                 GHOST_GetModifierKeyState(g_system, right, &val);
340         
341         return val;
342 }
343
344 static int change_bit(int val, int bit, int to_on) {
345         return to_on?(val|bit):(val&~bit);
346 }
347
348 static int event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) 
349 {
350         GHOST_TEventType type= GHOST_GetEventType(evt);
351
352         if (type == GHOST_kEventQuit) {
353                 exit_usiblender();
354         } else {
355                 GHOST_WindowHandle ghostwin= GHOST_GetEventWindow(evt);
356                 GHOST_TEventDataPtr data= GHOST_GetEventData(evt);
357                 Window *win;
358                 
359                 if (!ghostwin) {
360                         printf("GHOST event error - no window - type: %d\n", type);
361                         return 1;
362                 } else if (!GHOST_ValidWindow(g_system, ghostwin)) {
363                         printf("GHOST event error - invalid window - win: %p\n", ghostwin);
364                         return 1;
365                 } else {
366                         win= GHOST_GetWindowUserData(ghostwin);
367                 }
368                 
369                 switch (type) {
370                 case GHOST_kEventCursorMove: {
371                         GHOST_TEventCursorData *cd= data;
372                         int cx, cy;
373                         
374                         GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
375                         win->lmouse[0]= cx;
376                         win->lmouse[1]= (win->size[1]-1) - cy;
377                         
378                         window_handle(win, MOUSEX, win->lmouse[0]);
379                         window_handle(win, MOUSEY, win->lmouse[1]);
380
381                         break;
382                 }
383                 case GHOST_kEventButtonDown:
384                 case GHOST_kEventButtonUp: {
385                         GHOST_TEventButtonData *bd= data;
386                         int val= (type==GHOST_kEventButtonDown);
387                         int bbut= convert_mbut(bd->button);
388                 
389                         if (bbut==LEFTMOUSE) {
390                                 if (val) {
391                                         if (win->commandqual) {
392                                                 bbut= win->faked_mbut= RIGHTMOUSE;
393                                         } else if ((win->lqual & LR_ALTKEY) && (U.flag & USER_TWOBUTTONMOUSE)) {
394                                                 /* finally, it actually USES the userpref! :) -intrr */
395                                                 bbut= win->faked_mbut= MIDDLEMOUSE;
396                                         }
397                                 } else {
398                                         if (win->faked_mbut) {
399                                                 bbut= win->faked_mbut;
400                                                 win->faked_mbut= 0;
401                                         }
402                                 }
403                         }
404
405                         if (bbut==LEFTMOUSE) {
406                                 win->lmbut= change_bit(win->lmbut, L_MOUSE, val);
407                         } else if (bbut==MIDDLEMOUSE) {
408                                 win->lmbut= change_bit(win->lmbut, M_MOUSE, val);
409                         } else {
410                                 win->lmbut= change_bit(win->lmbut, R_MOUSE, val);
411                         }
412                         window_handle(win, bbut, val);
413                         
414                         break;
415                 }
416         
417                 case GHOST_kEventKeyDown:
418                 case GHOST_kEventKeyUp: {
419                         GHOST_TEventKeyData *kd= data;
420                         int val= (type==GHOST_kEventKeyDown);
421                         int bkey= convert_key(kd->key);
422
423                         if (kd->key == GHOST_kKeyCommand) {
424                                 win->commandqual= val;
425                         }
426
427                         if (bkey) {
428                                 if (bkey==LEFTSHIFTKEY || bkey==RIGHTSHIFTKEY) {
429                                         win->lqual= change_bit(win->lqual, LR_SHIFTKEY, val);
430                                 } else if (bkey==LEFTCTRLKEY || bkey==RIGHTCTRLKEY) {
431                                         win->lqual= change_bit(win->lqual, LR_CTRLKEY, val);
432                                 } else if (bkey==LEFTALTKEY || bkey==RIGHTALTKEY) {
433                                         win->lqual= change_bit(win->lqual, LR_ALTKEY, val);
434                                 }
435
436                                 window_handle_ext(win, bkey, val, kd->ascii);
437                         }
438                         
439                         break;
440                 }
441
442                 case GHOST_kEventWheel: {
443                         GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*) data;
444                         if (wheelData->z > 0) {
445                                 window_handle(win, WHEELUPMOUSE, 1);
446                         } else {
447                                 window_handle(win, WHEELDOWNMOUSE, 1);
448                         }
449                         break;
450                 }
451
452                 case GHOST_kEventWindowDeactivate:
453                 case GHOST_kEventWindowActivate: {
454                         win->active= (type==GHOST_kEventWindowActivate);
455                         window_handle(win, INPUTCHANGE, win->active);
456                         
457                         if (win->active) {
458                                 if ((win->lqual & LR_SHIFTKEY) && !query_qual('s')) {
459                                         win->lqual= change_bit(win->lqual, LR_SHIFTKEY, 0);
460                                         window_handle(win, LEFTSHIFTKEY, 0);
461                                 }
462                                 if ((win->lqual & LR_CTRLKEY) && !query_qual('c')) {
463                                         win->lqual= change_bit(win->lqual, LR_CTRLKEY, 0);
464                                         window_handle(win, LEFTCTRLKEY, 0);
465                                 }
466                                 if ((win->lqual & LR_ALTKEY) && !query_qual('a')) {
467                                         win->lqual= change_bit(win->lqual, LR_ALTKEY, 0);
468                                         window_handle(win, LEFTALTKEY, 0);
469                                 }
470                                 win->commandqual= query_qual('C');
471
472                                 /* 
473                                  * XXX quick hack so OSX version works better
474                                  * when the window is clicked on (focused).
475                                  *
476                                  * it used to pass on the old win->lmouse value,
477                                  * which causes a wrong click in Blender.
478                                  * Actually, a 'focus' click should not be passed
479                                  * on to blender... (ton)
480                                  */
481                                 if(1) { /* enables me to add locals */
482                                         int cx, cy, wx, wy;
483                                         GHOST_GetCursorPosition(g_system, &wx, &wy);
484
485                                         GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
486                                         win->lmouse[0]= cx;
487                                         win->lmouse[1]= (win->size[1]-1) - cy;
488                                         window_handle(win, MOUSEX, win->lmouse[0]);
489                                         window_handle(win, MOUSEY, win->lmouse[1]);
490                                 }
491                         }
492                         
493                         break;
494                 }
495                 case GHOST_kEventWindowClose: {
496                         window_handle(win, WINCLOSE, 1);
497                         break;
498                 }
499                 case GHOST_kEventWindowUpdate: {
500                         window_handle(win, REDRAW, 1);
501                         break;
502                 }
503                 case GHOST_kEventWindowSize: {
504                         GHOST_RectangleHandle client_rect;
505                         int l, t, r, b, scr_w, scr_h;
506
507                         client_rect= GHOST_GetClientBounds(win->ghostwin);
508                         GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
509                         
510                         GHOST_DisposeRectangle(client_rect);
511                         
512                         winlay_get_screensize(&scr_w, &scr_h);
513                         win->position[0]= l;
514                         win->position[1]= scr_h - b - 1;
515                         win->size[0]= r-l;
516                         win->size[1]= b-t;
517
518                         window_handle(win, RESHAPE, 1);
519                         break;
520                 }
521         }
522         }
523         
524         return 1;
525 }
526
527 char *window_get_title(Window *win) {
528         char *title= GHOST_GetTitle(win->ghostwin);
529         char *mem_title= BLI_strdup(title);
530         free(title);
531
532         return mem_title;
533 }
534
535 void window_set_title(Window *win, char *title) {
536         GHOST_SetTitle(win->ghostwin, title);
537 }
538
539 short window_get_qual(Window *win) {
540         return win->lqual;
541 }
542
543 short window_get_mbut(Window *win) {
544         return win->lmbut;
545 }
546
547 void window_get_mouse(Window *win, short *mval) {
548         mval[0]= win->lmouse[0];
549         mval[1]= win->lmouse[1];
550 }
551
552 void window_get_position(Window *win, int *posx_r, int *posy_r) {
553         *posx_r= win->position[0];
554         *posy_r= win->position[1];
555 }
556
557 void window_get_size(Window *win, int *width_r, int *height_r) {
558         *width_r= win->size[0];
559         *height_r= win->size[1];
560 }
561
562 void window_set_size(Window *win, int width, int height) {
563         GHOST_SetClientSize(win->ghostwin, width, height);
564 }
565
566 void window_lower(Window *win) {
567         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
568 }
569
570 void window_raise(Window *win) {
571         GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
572 }
573
574 #ifdef _WIN32   //FULLSCREEN
575 void window_toggle_fullscreen(Window *win, int fullscreen) {
576         /* these two lines make sure front and backbuffer are equal. for swapbuffers */
577         markdirty_all();
578         screen_swapbuffers();
579
580         if(fullscreen)
581                 GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateFullScreen);
582         else
583                 GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateMaximized);
584 }
585 #endif
586
587 void window_warp_pointer(Window *win, int x, int y) {
588         y= win->size[1] - y - 1;
589         GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y);
590         GHOST_SetCursorPosition(g_system, x, y);
591 }
592
593 void window_queue_redraw(Window *win) {
594         GHOST_InvalidateWindow(win->ghostwin); // ghost will send back a redraw to blender
595 }
596
597 /***/
598
599 void winlay_process_events(int wait_for_event) {
600         GHOST_ProcessEvents(g_system, wait_for_event);
601         GHOST_DispatchEvents(g_system);
602 }
603
604 void winlay_get_screensize(int *width_r, int *height_r) {
605         unsigned int uiwidth;
606         unsigned int uiheight;
607         
608         if (!g_system) {
609                 GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(event_proc, NULL);
610         
611                 g_system= GHOST_CreateSystem();
612                 GHOST_AddEventConsumer(g_system, consumer);
613         }
614         
615         GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
616         *width_r= uiwidth;
617         *height_r= uiheight;
618 }
619
620 Window *winlay_get_active_window(void) {
621         return active_gl_window;
622 }