1/* vi:set ts=8 sw=4 sts=4: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * Photon GUI support by Julian Kinraid 5 * 6 * Do ":help uganda" in Vim to read copying and usage conditions. 7 * Do ":help credits" in Vim to see a list of people who contributed. 8 * 9 * 10 * Clipboard support is in os_qnx.c 11 * PhAttach() is called in os_qnx.c:qnx_init() 12 */ 13 14#include "vim.h" 15 16#ifdef FEAT_TOOLBAR 17# include <photon/PxImage.h> 18#endif 19 20#if !defined(__QNX__) 21/* Used when generating prototypes. */ 22# define PgColor_t int 23# define PhEvent_t int 24# define PhPoint_t int 25# define PtWidget_t int 26# define Pg_BLACK 0 27# define PtCallbackF_t int 28# define PtCallbackInfo_t int 29# define PhTile_t int 30# define PtWidget_t int 31# define PhImage_t int 32#endif 33 34#define ARRAY_LENGTH(a) (sizeof(a) / sizeof(a[0])) 35#define RGB(r,g,b) PgRGB(r,g,b) 36 37#define EVENT_BUFFER_SIZE sizeof( PhEvent_t ) + 1000 38 39/* Some defines for gui_mch_mousehide() */ 40#define MOUSE_HIDE TRUE 41#define MOUSE_SHOW FALSE 42 43/* Optional support for using a PtPanelGroup widget, needs work */ 44#undef USE_PANEL_GROUP 45 46#ifdef USE_PANEL_GROUP 47static char *empty_title = " "; 48static char **panel_titles = NULL; 49static ushort_t num_panels = 0; 50static short pg_margin_left, pg_margin_right, pg_margin_top, pg_margin_bottom; 51#endif 52 53#define GUI_PH_MARGIN 4 /* Size of the bevel */ 54 55#define GUI_PH_MOUSE_TYPE Ph_CURSOR_INSERT 56static PgColor_t gui_ph_mouse_color = Pg_BLACK; 57 58static PhPoint_t gui_ph_raw_offset; 59static PtWidget_t *gui_ph_timer_cursor; /* handle cursor blinking */ 60static PtWidget_t *gui_ph_timer_timeout; /* used in gui_mch_wait_for_chars */ 61static short is_timeout; /* Has the timeout occured? */ 62 63/* 64 * This is set inside the mouse callback for a right mouse 65 * button click, and used for the popup menus 66 */ 67static PhPoint_t abs_mouse; 68 69/* Try and avoid redraws while a resize is in progress */ 70static int is_ignore_draw = FALSE; 71 72/* Used for converting to/from utf-8 and other charsets */ 73static struct PxTransCtrl *charset_translate; 74 75/* 76 * Cursor blink functions. 77 * 78 * This is a simple state machine: 79 * BLINK_NONE not blinking at all 80 * BLINK_OFF blinking, cursor is not shown 81 * BLINK_ON blinking, cursor is shown 82 */ 83static enum { 84 BLINK_NONE, 85 BLINK_OFF, 86 BLINK_ON 87} blink_state = BLINK_NONE; 88 89static long_u blink_waittime = 700; 90static long_u blink_ontime = 400; 91static long_u blink_offtime = 250; 92 93static struct 94{ 95 int key_sym; 96 char_u vim_code0; 97 char_u vim_code1; 98} special_keys[] = 99{ 100 {Pk_Up, 'k', 'u'}, 101 {Pk_Down, 'k', 'd'}, 102 {Pk_Left, 'k', 'l'}, 103 {Pk_Right, 'k', 'r'}, 104 105 {Pk_F1, 'k', '1'}, 106 {Pk_F2, 'k', '2'}, 107 {Pk_F3, 'k', '3'}, 108 {Pk_F4, 'k', '4'}, 109 {Pk_F5, 'k', '5'}, 110 {Pk_F6, 'k', '6'}, 111 {Pk_F7, 'k', '7'}, 112 {Pk_F8, 'k', '8'}, 113 {Pk_F9, 'k', '9'}, 114 {Pk_F10, 'k', ';'}, 115 116 {Pk_F11, 'F', '1'}, 117 {Pk_F12, 'F', '2'}, 118 {Pk_F13, 'F', '3'}, 119 {Pk_F14, 'F', '4'}, 120 {Pk_F15, 'F', '5'}, 121 {Pk_F16, 'F', '6'}, 122 {Pk_F17, 'F', '7'}, 123 {Pk_F18, 'F', '8'}, 124 {Pk_F19, 'F', '9'}, 125 {Pk_F20, 'F', 'A'}, 126 127 {Pk_F21, 'F', 'B'}, 128 {Pk_F22, 'F', 'C'}, 129 {Pk_F23, 'F', 'D'}, 130 {Pk_F24, 'F', 'E'}, 131 {Pk_F25, 'F', 'F'}, 132 {Pk_F26, 'F', 'G'}, 133 {Pk_F27, 'F', 'H'}, 134 {Pk_F28, 'F', 'I'}, 135 {Pk_F29, 'F', 'J'}, 136 137 {Pk_F30, 'F', 'K'}, 138 {Pk_F31, 'F', 'L'}, 139 {Pk_F32, 'F', 'M'}, 140 {Pk_F33, 'F', 'N'}, 141 {Pk_F34, 'F', 'O'}, 142 {Pk_F35, 'F', 'P'}, 143 144 {Pk_Help, '%', '1'}, 145 {Pk_BackSpace, 'k', 'b'}, 146 {Pk_Insert, 'k', 'I'}, 147 {Pk_Delete, 'k', 'D'}, 148 {Pk_Home, 'k', 'h'}, 149 {Pk_End, '@', '7'}, 150 {Pk_Prior, 'k', 'P'}, 151 {Pk_Next, 'k', 'N'}, 152 {Pk_Print, '%', '9'}, 153 154 {Pk_KP_Add, 'K', '6'}, 155 {Pk_KP_Subtract,'K', '7'}, 156 {Pk_KP_Divide, 'K', '8'}, 157 {Pk_KP_Multiply,'K', '9'}, 158 {Pk_KP_Enter, 'K', 'A'}, 159 160 {Pk_KP_0, KS_EXTRA, KE_KINS}, /* Insert */ 161 {Pk_KP_Decimal, KS_EXTRA, KE_KDEL}, /* Delete */ 162 163 {Pk_KP_4, 'k', 'l'}, /* Left */ 164 {Pk_KP_6, 'k', 'r'}, /* Right */ 165 {Pk_KP_8, 'k', 'u'}, /* Up */ 166 {Pk_KP_2, 'k', 'd'}, /* Down */ 167 168 {Pk_KP_7, 'K', '1'}, /* Home */ 169 {Pk_KP_1, 'K', '4'}, /* End */ 170 171 {Pk_KP_9, 'K', '3'}, /* Page Up */ 172 {Pk_KP_3, 'K', '5'}, /* Page Down */ 173 174 {Pk_KP_5, '&', '8'}, /* Undo */ 175 176 /* Keys that we want to be able to use any modifier with: */ 177 {Pk_Return, CAR, NUL}, 178 {Pk_space, ' ', NUL}, 179 {Pk_Tab, TAB, NUL}, 180 {Pk_Escape, ESC, NUL}, 181 {NL, NL, NUL}, 182 {CAR, CAR, NUL}, 183 184 /* End of list marker: */ 185 {0, 0, 0} 186}; 187 188 189/****************************************************************************/ 190 191static PtCallbackF_t gui_ph_handle_timer_cursor; 192static PtCallbackF_t gui_ph_handle_timer_timeout; 193 194static PtCallbackF_t gui_ph_handle_window_cb; 195 196static PtCallbackF_t gui_ph_handle_scrollbar; 197static PtCallbackF_t gui_ph_handle_keyboard; 198static PtCallbackF_t gui_ph_handle_mouse; 199static PtCallbackF_t gui_ph_handle_pulldown_menu; 200static PtCallbackF_t gui_ph_handle_menu; 201static PtCallbackF_t gui_ph_handle_focus; /* focus change of text area */ 202 203static PtCallbackF_t gui_ph_handle_menu_resize; 204 205/* When a menu is unrealized, give focus back to vimTextArea */ 206static PtCallbackF_t gui_ph_handle_menu_unrealized; 207 208#ifdef USE_PANEL_GROUP 209static void gui_ph_get_panelgroup_margins( short*, short*, short*, short* ); 210#endif 211 212#ifdef FEAT_TOOLBAR 213static PhImage_t *gui_ph_toolbar_find_icon( vimmenu_T *menu ); 214#endif 215 216static void gui_ph_draw_start( void ); 217static void gui_ph_draw_end( void ); 218 219/* Set the text for the balloon */ 220static PtWidget_t * gui_ph_show_tooltip( PtWidget_t *window, 221 PtWidget_t *widget, 222 int position, 223 char *text, 224 char *font, 225 PgColor_t fill_color, 226 PgColor_t text_color ); 227 228/****************************************************************************/ 229 230static PtWidget_t * gui_ph_show_tooltip( PtWidget_t *window, 231 PtWidget_t *widget, 232 int position, 233 char *text, 234 char *font, 235 PgColor_t fill_color, 236 PgColor_t text_color ) 237{ 238 PtArg_t arg; 239 vimmenu_T *menu; 240 char_u *tooltip; 241 242 PtSetArg( &arg, Pt_ARG_POINTER, &menu, 0 ); 243 PtGetResources( widget, 1, &arg ); 244 245 /* Override the text and position */ 246 247 tooltip = text; 248 if( menu != NULL ) 249 { 250 int index = MENU_INDEX_TIP; 251 if( menu->strings[ index ] != NULL ) 252 tooltip = menu->strings[ index ]; 253 } 254 255 return( PtInflateBalloon( 256 window, 257 widget, 258 /* Don't put the balloon at the bottom, 259 * it gets drawn over by gfx done in the PtRaw */ 260 Pt_BALLOON_TOP, 261 tooltip, 262 font, 263 fill_color, 264 text_color ) ); 265} 266 267 static void 268gui_ph_resize_container( void ) 269{ 270 PhArea_t area; 271 272 PtWidgetArea( gui.vimWindow, &area ); 273 PtWidgetPos ( gui.vimContainer, &area.pos ); 274 275 PtSetResource( gui.vimContainer, Pt_ARG_AREA, &area, 0 ); 276} 277 278 static int 279gui_ph_handle_menu_resize( 280 PtWidget_t *widget, 281 void *other, 282 PtCallbackInfo_t *info ) 283{ 284 PtContainerCallback_t *sizes = info->cbdata; 285 PtWidget_t *container; 286 PhPoint_t below_menu; 287 int_u height; 288 289 height = sizes->new_dim.h; 290 291 /* Because vim treats the toolbar and menubar separately, 292 * and here they're lumped together into a PtToolbarGroup, 293 * we only need either menu_height or toolbar_height set at once */ 294 if( gui.menu_is_active ) 295 { 296 gui.menu_height = height; 297 gui.toolbar_height = 0; 298 } 299#ifdef FEAT_TOOLBAR 300 else 301 gui.toolbar_height = height; 302#endif 303 304 below_menu.x = 0; 305 below_menu.y = height; 306 307#ifdef USE_PANEL_GROUP 308 container = gui.vimPanelGroup; 309#else 310 container = gui.vimContainer; 311#endif 312 313 PtSetResource( container, Pt_ARG_POS, &below_menu, 0 ); 314 315 gui_ph_resize_container(); 316 317#ifdef USE_PANEL_GROUP 318 gui_ph_get_panelgroup_margins( 319 &pg_margin_top, &pg_margin_bottom, 320 &pg_margin_left, &pg_margin_right ); 321#endif 322 return( Pt_CONTINUE ); 323} 324 325/* 326 * Pt_ARG_TIMER_REPEAT isn't used because the on & off times 327 * are different 328 */ 329 static int 330gui_ph_handle_timer_cursor( 331 PtWidget_t *widget, 332 void *data, 333 PtCallbackInfo_t *info ) 334{ 335 if( blink_state == BLINK_ON ) 336 { 337 gui_undraw_cursor(); 338 blink_state = BLINK_OFF; 339 PtSetResource( gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 340 blink_offtime, 0 ); 341 } 342 else 343 { 344 gui_update_cursor(TRUE, FALSE); 345 blink_state = BLINK_ON; 346 PtSetResource( gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 347 blink_ontime, 0 ); 348 } 349 return( Pt_CONTINUE ); 350} 351 352 static int 353gui_ph_handle_timer_timeout(PtWidget_t *widget, void *data, PtCallbackInfo_t *info) 354{ 355 is_timeout = TRUE; 356 357 return( Pt_CONTINUE ); 358} 359 360 static int 361gui_ph_handle_window_cb( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 362{ 363 PhWindowEvent_t *we = info->cbdata; 364 ushort_t *width, *height; 365 366 switch( we->event_f ) { 367 case Ph_WM_CLOSE: 368 gui_shell_closed(); 369 break; 370 371 case Ph_WM_FOCUS: 372 /* Just in case it's hidden and needs to be shown */ 373 gui_mch_mousehide( MOUSE_SHOW ); 374 375 if( we->event_state == Ph_WM_EVSTATE_FOCUS ) 376 { 377 gui_focus_change(TRUE); 378 gui_mch_start_blink(); 379 } 380 else 381 { 382 gui_focus_change(FALSE); 383 gui_mch_stop_blink(); 384 } 385 break; 386 387 case Ph_WM_RESIZE: 388 PtGetResource( gui.vimWindow, Pt_ARG_WIDTH, &width, 0 ); 389 PtGetResource( gui.vimWindow, Pt_ARG_HEIGHT, &height, 0 ); 390#ifdef USE_PANEL_GROUP 391 width -= (pg_margin_left + pg_margin_right); 392 height -= (pg_margin_top + pg_margin_bottom); 393#endif 394 gui_resize_shell( *width, *height ); 395 gui_set_shellsize( FALSE, FALSE, RESIZE_BOTH ); 396 is_ignore_draw = FALSE; 397 PtEndFlux( gui.vimContainer ); 398 PtContainerRelease( gui.vimContainer ); 399 break; 400 401 default: 402 break; 403 } 404 405 return( Pt_CONTINUE ); 406} 407 408 static int 409gui_ph_handle_scrollbar( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 410{ 411 PtScrollbarCallback_t *scroll; 412 scrollbar_T *sb; 413 int value, dragging = FALSE; 414 415 scroll = info->cbdata; 416 417 sb = (scrollbar_T *) data; 418 if( sb != NULL ) 419 { 420 value = scroll->position; 421 switch( scroll->action ) 422 { 423 case Pt_SCROLL_DRAGGED: 424 dragging = TRUE; 425 break; 426 427 case Pt_SCROLL_SET: 428 /* FIXME: return straight away here? */ 429 return( Pt_CONTINUE ); 430 break; 431 } 432 433 gui_drag_scrollbar(sb, value, dragging); 434 } 435 return( Pt_CONTINUE ); 436} 437 438 static int 439gui_ph_handle_keyboard( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 440{ 441 PhKeyEvent_t *key; 442 unsigned char string[6]; 443 int len, i; 444 int ch, modifiers; 445 446 key = PhGetData( info->event ); 447 448 ch = modifiers = len = 0; 449 450 if( p_mh ) 451 gui_mch_mousehide( MOUSE_HIDE ); 452 453 /* We're a good lil photon program, aren't we? yes we are, yeess wee arrr */ 454 if( key->key_flags & Pk_KF_Compose ) 455 { 456 return( Pt_CONTINUE ); 457 } 458 459 if( (key->key_flags & Pk_KF_Cap_Valid) && 460 PkIsKeyDown( key->key_flags ) ) 461 { 462#ifdef FEAT_MENU 463 /* 464 * Only show the menu if the Alt key is down, and the Shift & Ctrl 465 * keys aren't down, as well as the other conditions 466 */ 467 if( ( ( key->key_mods & Pk_KM_Alt ) && 468 !( key->key_mods & Pk_KM_Shift ) && 469 !( key->key_mods & Pk_KM_Ctrl ) ) && 470 gui.menu_is_active && 471 ( *p_wak == 'y' || 472 ( *p_wak == 'm' && 473 gui_is_menu_shortcut( key->key_cap ) ) ) ) 474 { 475 /* Fallthrough and let photon look for the hotkey */ 476 return( Pt_CONTINUE ); 477 } 478#endif 479 480 for( i = 0; special_keys[i].key_sym != 0; i++ ) 481 { 482 if( special_keys[i].key_sym == key->key_cap ) 483 { 484 len = 0; 485 if( special_keys[i].vim_code1 == NUL ) 486 ch = special_keys[i].vim_code0; 487 else 488 { 489 /* Detect if a keypad number key has been pressed 490 * and change the key if Num Lock is on */ 491 if( key->key_cap >= Pk_KP_Enter && key->key_cap <= Pk_KP_9 492 && ( key->key_mods & Pk_KM_Num_Lock ) ) 493 { 494 /* FIXME: For now, just map the key to a ascii value 495 * (see <photon/PkKeyDef.h>) */ 496 ch = key->key_cap - 0xf080; 497 } 498 else 499 ch = TO_SPECIAL( special_keys[i].vim_code0, 500 special_keys[i].vim_code1 ); 501 } 502 break; 503 } 504 } 505 506 if( key->key_mods & Pk_KM_Ctrl ) 507 modifiers |= MOD_MASK_CTRL; 508 if( key->key_mods & Pk_KM_Alt ) 509 modifiers |= MOD_MASK_ALT; 510 if( key->key_mods & Pk_KM_Shift ) 511 modifiers |= MOD_MASK_SHIFT; 512 513 /* Is this not a special key? */ 514 if( special_keys[i].key_sym == 0 ) 515 { 516 ch = PhTo8859_1( key ); 517 if( ch == -1 518#ifdef FEAT_MBYTE 519 || ( enc_utf8 && ch > 127 ) 520#endif 521 ) 522 { 523#ifdef FEAT_MBYTE 524 len = PhKeyToMb( string, key ); 525 if( len > 0 ) 526 { 527 static char buf[6]; 528 int src_taken, dst_made; 529 if( enc_utf8 != TRUE ) 530 { 531 PxTranslateFromUTF( 532 charset_translate, 533 string, 534 len, 535 &src_taken, 536 buf, 537 6, 538 &dst_made ); 539 540 add_to_input_buf( buf, dst_made ); 541 } 542 else 543 { 544 add_to_input_buf( string, len ); 545 } 546 547 return( Pt_CONSUME ); 548 } 549 len = 0; 550#endif 551 ch = key->key_cap; 552 if( ch < 0xff ) 553 { 554 /* FIXME: is this the right thing to do? */ 555 if( modifiers & MOD_MASK_CTRL ) 556 { 557 modifiers &= ~MOD_MASK_CTRL; 558 559 if( ( ch >= 'a' && ch <= 'z' ) || 560 ch == '[' || 561 ch == ']' || 562 ch == '\\' ) 563 ch = Ctrl_chr( ch ); 564 else if( ch == '2' ) 565 ch = NUL; 566 else if( ch == '6' ) 567 ch = 0x1e; 568 else if( ch == '-' ) 569 ch = 0x1f; 570 else 571 modifiers |= MOD_MASK_CTRL; 572 } 573 574 if( modifiers & MOD_MASK_ALT ) 575 { 576 ch = Meta( ch ); 577 modifiers &= ~MOD_MASK_ALT; 578 } 579 } 580 else 581 { 582 return( Pt_CONTINUE ); 583 } 584 } 585 else 586 modifiers &= ~MOD_MASK_SHIFT; 587 } 588 589 ch = simplify_key( ch, &modifiers ); 590 if( modifiers ) 591 { 592 string[ len++ ] = CSI; 593 string[ len++ ] = KS_MODIFIER; 594 string[ len++ ] = modifiers; 595 } 596 597 if( IS_SPECIAL( ch ) ) 598 { 599 string[ len++ ] = CSI; 600 string[ len++ ] = K_SECOND( ch ); 601 string[ len++ ] = K_THIRD( ch ); 602 } 603 else 604 { 605 string[ len++ ] = ch; 606 } 607 608 if (len == 1 && ((ch == Ctrl_C && ctrl_c_interrupts) 609 || ch == intr_char)) 610 { 611 trash_input_buf(); 612 got_int = TRUE; 613 } 614 615 if (len == 1 && string[0] == CSI) 616 { 617 /* Turn CSI into K_CSI. */ 618 string[ len++ ] = KS_EXTRA; 619 string[ len++ ] = KE_CSI; 620 } 621 622 if( len > 0 ) 623 { 624 add_to_input_buf( string, len ); 625 return( Pt_CONSUME ); 626 } 627 } 628 629 return( Pt_CONTINUE ); 630} 631 632 static int 633gui_ph_handle_mouse( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 634{ 635 PhPointerEvent_t *pointer; 636 PhRect_t *pos; 637 int button = 0, repeated_click, modifiers = 0x0; 638 short mouse_x, mouse_y; 639 640 pointer = PhGetData( info->event ); 641 pos = PhGetRects( info->event ); 642 643 gui_mch_mousehide( MOUSE_SHOW ); 644 645 /* 646 * Coordinates need to be relative to the base window, 647 * not relative to the vimTextArea widget 648 */ 649 mouse_x = pos->ul.x + gui.border_width; 650 mouse_y = pos->ul.y + gui.border_width; 651 652 if( info->event->type == Ph_EV_PTR_MOTION_NOBUTTON ) 653 { 654 gui_mouse_moved( mouse_x, mouse_y ); 655 return( Pt_CONTINUE ); 656 } 657 658 if( pointer->key_mods & Pk_KM_Shift ) 659 modifiers |= MOUSE_SHIFT; 660 if( pointer->key_mods & Pk_KM_Ctrl ) 661 modifiers |= MOUSE_CTRL; 662 if( pointer->key_mods & Pk_KM_Alt ) 663 modifiers |= MOUSE_ALT; 664 665 /* 666 * FIXME More than one button may be involved, but for 667 * now just deal with one 668 */ 669 if( pointer->buttons & Ph_BUTTON_SELECT ) 670 button = MOUSE_LEFT; 671 672 if( pointer->buttons & Ph_BUTTON_MENU ) 673 { 674 button = MOUSE_RIGHT; 675 /* Need the absolute coordinates for the popup menu */ 676 abs_mouse.x = pointer->pos.x; 677 abs_mouse.y = pointer->pos.y; 678 } 679 680 if( pointer->buttons & Ph_BUTTON_ADJUST ) 681 button = MOUSE_MIDDLE; 682 683 /* Catch a real release (not phantom or other releases */ 684 if( info->event->type == Ph_EV_BUT_RELEASE ) 685 button = MOUSE_RELEASE; 686 687 if( info->event->type & Ph_EV_PTR_MOTION_BUTTON ) 688 button = MOUSE_DRAG; 689 690#if 0 691 /* Vim doesn't use button repeats */ 692 if( info->event->type & Ph_EV_BUT_REPEAT ) 693 button = MOUSE_DRAG; 694#endif 695 696 /* Don't do anything if it is one of the phantom mouse release events */ 697 if( ( button != MOUSE_RELEASE ) || 698 ( info->event->subtype == Ph_EV_RELEASE_REAL ) ) 699 { 700 repeated_click = (pointer->click_count >= 2) ? TRUE : FALSE; 701 702 gui_send_mouse_event( button , mouse_x, mouse_y, repeated_click, modifiers ); 703 } 704 705 return( Pt_CONTINUE ); 706} 707 708/* Handle a focus change of the PtRaw widget */ 709 static int 710gui_ph_handle_focus( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 711{ 712 if( info->reason == Pt_CB_LOST_FOCUS ) 713 { 714 PtRemoveEventHandler( gui.vimTextArea, Ph_EV_PTR_MOTION_NOBUTTON, 715 gui_ph_handle_mouse, NULL ); 716 717 gui_mch_mousehide( MOUSE_SHOW ); 718 } 719 else 720 { 721 PtAddEventHandler( gui.vimTextArea, Ph_EV_PTR_MOTION_NOBUTTON, 722 gui_ph_handle_mouse, NULL ); 723 } 724 return( Pt_CONTINUE ); 725} 726 727 static void 728gui_ph_handle_raw_draw( PtWidget_t *widget, PhTile_t *damage ) 729{ 730 PhRect_t *r; 731 PhPoint_t offset; 732 PhPoint_t translation; 733 734 if( is_ignore_draw == TRUE ) 735 return; 736 737 PtSuperClassDraw( PtBasic, widget, damage ); 738 PgGetTranslation( &translation ); 739 PgClearTranslation(); 740 741#if 0 742 /* 743 * This causes some weird problems, with drawing being done from 744 * within this raw drawing function (rather than just simple clearing 745 * and text drawing done by gui_redraw) 746 * 747 * The main problem is when PhBlit is used, and the cursor appearing 748 * in places where it shouldn't 749 */ 750 out_flush(); 751#endif 752 753 PtWidgetOffset( widget, &offset ); 754 PhTranslatePoint( &offset, PtWidgetPos( gui.vimTextArea, NULL ) ); 755 756#if 1 757 /* Redraw individual damage regions */ 758 if( damage->next != NULL ) 759 damage = damage->next; 760 761 while( damage != NULL ) 762 { 763 r = &damage->rect; 764 gui_redraw( 765 r->ul.x - offset.x, r->ul.y - offset.y, 766 r->lr.x - r->ul.x + 1, 767 r->lr.y - r->ul.y + 1 ); 768 damage = damage->next; 769 } 770#else 771 /* Redraw the rectangle that covers all the damaged regions */ 772 r = &damage->rect; 773 gui_redraw( 774 r->ul.x - offset.x, r->ul.y - offset.y, 775 r->lr.x - r->ul.x + 1, 776 r->lr.y - r->ul.y + 1 ); 777#endif 778 779 PgSetTranslation( &translation, 0 ); 780} 781 782 static int 783gui_ph_handle_pulldown_menu( 784 PtWidget_t *widget, 785 void *data, 786 PtCallbackInfo_t *info ) 787{ 788 if( data != NULL ) 789 { 790 vimmenu_T *menu = (vimmenu_T *) data; 791 792 PtPositionMenu( menu->submenu_id, NULL ); 793 PtRealizeWidget( menu->submenu_id ); 794 } 795 796 return( Pt_CONTINUE ); 797} 798 799/* This is used for pulldown/popup menus and also toolbar buttons */ 800 static int 801gui_ph_handle_menu( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 802{ 803 if( data != NULL ) 804 { 805 vimmenu_T *menu = (vimmenu_T *) data; 806 gui_menu_cb( menu ); 807 } 808 return( Pt_CONTINUE ); 809} 810 811/* Stop focus from disappearing into the menubar... */ 812 static int 813gui_ph_handle_menu_unrealized( 814 PtWidget_t *widget, 815 void *data, 816 PtCallbackInfo_t *info ) 817{ 818 PtGiveFocus( gui.vimTextArea, NULL ); 819 return( Pt_CONTINUE ); 820} 821 822 static int 823gui_ph_handle_window_open( 824 PtWidget_t *widget, 825 void *data, 826 PtCallbackInfo_t *info ) 827{ 828 gui_set_shellsize( FALSE, TRUE, RESIZE_BOTH ); 829 return( Pt_CONTINUE ); 830} 831 832/****************************************************************************/ 833 834#define DRAW_START gui_ph_draw_start() 835#define DRAW_END gui_ph_draw_end() 836 837/* TODO: Set a clipping rect? */ 838 static void 839gui_ph_draw_start( void ) 840{ 841 PhGC_t *gc; 842 843 gc = PgGetGC(); 844 PgSetRegion( PtWidgetRid( PtFindDisjoint( gui.vimTextArea ) ) ); 845 PgClearClippingsCx( gc ); 846 PgClearTranslationCx( gc ); 847 848 PtWidgetOffset( gui.vimTextArea, &gui_ph_raw_offset ); 849 PhTranslatePoint( &gui_ph_raw_offset, PtWidgetPos( gui.vimTextArea, NULL ) ); 850 851 PgSetTranslation( &gui_ph_raw_offset, Pg_RELATIVE ); 852} 853 854 static void 855gui_ph_draw_end( void ) 856{ 857 gui_ph_raw_offset.x = -gui_ph_raw_offset.x; 858 gui_ph_raw_offset.y = -gui_ph_raw_offset.y; 859 PgSetTranslation( &gui_ph_raw_offset, Pg_RELATIVE ); 860} 861 862#ifdef USE_PANEL_GROUP 863 static vimmenu_T * 864gui_ph_find_buffer_item( char_u *name ) 865{ 866 vimmenu_T *top_level = root_menu; 867 vimmenu_T *items = NULL; 868 869 while( top_level != NULL && 870 ( STRCMP( top_level->dname, "Buffers" ) != 0 ) ) 871 top_level = top_level->next; 872 873 if( top_level != NULL ) 874 { 875 items = top_level->children; 876 877 while( items != NULL && 878 ( STRCMP( items->dname, name ) != 0 ) ) 879 items = items->next; 880 } 881 return( items ); 882} 883 884 static void 885gui_ph_pg_set_buffer_num( int_u buf_num ) 886{ 887 int i; 888 char search[16]; 889 char *mark; 890 891 if( gui.vimTextArea == NULL || buf_num == 0 ) 892 return; 893 894 search[0] = '('; 895 ultoa( buf_num, &search[1], 10 ); 896 STRCAT( search, ")" ); 897 898 for( i = 0; i < num_panels; i++ ) 899 { 900 /* find the last "(" in the panel title and see if the buffer 901 * number in the title matches the one we're looking for */ 902 mark = STRRCHR( panel_titles[ i ], '(' ); 903 if( mark != NULL && STRCMP( mark, search ) == 0 ) 904 { 905 PtSetResource( gui.vimPanelGroup, Pt_ARG_PG_CURRENT_INDEX, 906 i, 0 ); 907 } 908 } 909} 910 911 static int 912gui_ph_handle_pg_change( 913 PtWidget_t *widget, 914 void *data, 915 PtCallbackInfo_t *info ) 916{ 917 vimmenu_T *menu; 918 PtPanelGroupCallback_t *panel; 919 920 if( info->event != NULL ) 921 { 922 panel = info->cbdata; 923 if( panel->new_panel != NULL ) 924 { 925 menu = gui_ph_find_buffer_item( panel->new_panel ); 926 if( menu ) 927 gui_menu_cb( menu ); 928 } 929 } 930 return( Pt_CONTINUE ); 931} 932 933 static void 934gui_ph_get_panelgroup_margins( 935 short *top, 936 short *bottom, 937 short *left, 938 short *right ) 939{ 940 unsigned short abs_raw_x, abs_raw_y, abs_panel_x, abs_panel_y; 941 const unsigned short *margin_top, *margin_bottom; 942 const unsigned short *margin_left, *margin_right; 943 944 PtGetAbsPosition( gui.vimTextArea, &abs_raw_x, &abs_raw_y ); 945 PtGetAbsPosition( gui.vimPanelGroup, &abs_panel_x, &abs_panel_y ); 946 947 PtGetResource( gui.vimPanelGroup, Pt_ARG_MARGIN_RIGHT, &margin_right, 0 ); 948 PtGetResource( gui.vimPanelGroup, Pt_ARG_MARGIN_BOTTOM, &margin_bottom, 0 ); 949 950 abs_raw_x -= abs_panel_x; 951 abs_raw_y -= abs_panel_y; 952 953 *top = abs_raw_y; 954 *bottom = *margin_bottom; 955 956 *left = abs_raw_x; 957 *right = *margin_right; 958} 959 960/* Used for the tabs for PtPanelGroup */ 961 static int 962gui_ph_is_buffer_item( vimmenu_T *menu, vimmenu_T *parent ) 963{ 964 char *mark; 965 966 if( STRCMP( parent->dname, "Buffers" ) == 0 ) 967 { 968 /* Look for '(' digits ')' */ 969 mark = vim_strchr( menu->dname, '(' ); 970 if( mark != NULL ) 971 { 972 mark++; 973 while( isdigit( *mark ) ) 974 mark++; 975 976 if( *mark == ')' ) 977 return( TRUE); 978 } 979 } 980 return( FALSE ); 981} 982 983 static void 984gui_ph_pg_add_buffer(char *name ) 985{ 986 char **new_titles = NULL; 987 988 new_titles = (char **) alloc( ( num_panels + 1 ) * sizeof( char ** ) ); 989 if( new_titles != NULL ) 990 { 991 if( num_panels > 0 ) 992 memcpy( new_titles, panel_titles, num_panels * sizeof( char ** ) ); 993 994 new_titles[ num_panels++ ] = name; 995 996 PtSetResource( gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, new_titles, 997 num_panels ); 998 999 vim_free( panel_titles ); 1000 panel_titles = new_titles; 1001 } 1002} 1003 1004 static void 1005gui_ph_pg_remove_buffer( char *name ) 1006{ 1007 int i; 1008 char **new_titles = NULL; 1009 1010 /* If there is only 1 panel, we just use the temporary place holder */ 1011 if( num_panels > 1 ) 1012 { 1013 new_titles = (char **) alloc( ( num_panels - 1 ) * sizeof( char ** ) ); 1014 if( new_titles != NULL ) 1015 { 1016 char **s = new_titles; 1017 /* Copy all the titles except the one we're removing */ 1018 for( i = 0; i < num_panels; i++ ) 1019 { 1020 if( STRCMP( panel_titles[ i ], name ) != 0 ) 1021 { 1022 *s++ = panel_titles[ i ]; 1023 } 1024 } 1025 num_panels--; 1026 1027 PtSetResource( gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, new_titles, 1028 num_panels ); 1029 1030 vim_free( panel_titles ); 1031 panel_titles = new_titles; 1032 } 1033 } 1034 else 1035 { 1036 num_panels--; 1037 PtSetResource( gui.vimPanelGroup, Pt_ARG_PG_PANEL_TITLES, &empty_title, 1038 1 ); 1039 1040 vim_free( panel_titles ); 1041 panel_titles = NULL; 1042 } 1043} 1044 1045/* When a buffer item is deleted from the buffer menu */ 1046 static int 1047gui_ph_handle_buffer_remove( 1048 PtWidget_t *widget, 1049 void *data, 1050 PtCallbackInfo_t *info ) 1051{ 1052 vimmenu_T *menu; 1053 1054 if( data != NULL ) 1055 { 1056 menu = (vimmenu_T *) data; 1057 gui_ph_pg_remove_buffer( menu->dname ); 1058 } 1059 1060 return( Pt_CONTINUE ); 1061} 1062#endif 1063 1064 static int 1065gui_ph_pane_resize( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 1066{ 1067 if( PtWidgetIsRealized( widget ) ) 1068 { 1069 is_ignore_draw = TRUE; 1070 PtStartFlux( gui.vimContainer ); 1071 PtContainerHold( gui.vimContainer ); 1072 } 1073 1074 return( Pt_CONTINUE ); 1075} 1076 1077/****************************************************************************/ 1078 1079#ifdef FEAT_MBYTE 1080 void 1081gui_ph_encoding_changed( int new_encoding ) 1082{ 1083 /* Default encoding is latin1 */ 1084 char *charset = "latin1"; 1085 int i; 1086 1087 struct { 1088 int encoding; 1089 char *name; 1090 } charsets[] = { 1091 { DBCS_JPN, "SHIFT_JIS" }, 1092 { DBCS_KOR, "csEUCKR" }, 1093 { DBCS_CHT, "big5" }, 1094 { DBCS_CHS, "gb" } 1095 }; 1096 1097 for( i = 0; i < ARRAY_LENGTH( charsets ); i++ ) 1098 { 1099 if( new_encoding == charsets[ i ].encoding ) 1100 charset = charsets[ i ].name; 1101 } 1102 1103 charset_translate = PxTranslateSet( charset_translate, charset ); 1104} 1105#endif 1106 1107/****************************************************************************/ 1108/****************************************************************************/ 1109 1110 void 1111gui_mch_prepare(argc, argv) 1112 int *argc; 1113 char **argv; 1114{ 1115 PtInit( NULL ); 1116} 1117 1118 int 1119gui_mch_init(void) 1120{ 1121 PtArg_t args[10]; 1122 int flags = 0, n = 0; 1123 1124 PhDim_t window_size = {100, 100}; /* Arbitrary values */ 1125 PhPoint_t pos = {0, 0}; 1126 1127 gui.event_buffer = (PhEvent_t *) alloc( EVENT_BUFFER_SIZE ); 1128 if( gui.event_buffer == NULL ) 1129 return( FAIL ); 1130 1131 /* Get a translation so we can convert from ISO Latin-1 to UTF */ 1132 charset_translate = PxTranslateSet( NULL, "latin1" ); 1133 1134 /* The +2 is for the 1 pixel dark line on each side */ 1135 gui.border_offset = gui.border_width = GUI_PH_MARGIN + 2; 1136 1137 /* Handle close events ourselves */ 1138 PtSetArg( &args[ n++ ], Pt_ARG_WINDOW_MANAGED_FLAGS, Pt_FALSE, Ph_WM_CLOSE ); 1139 PtSetArg( &args[ n++ ], Pt_ARG_WINDOW_NOTIFY_FLAGS, Pt_TRUE, 1140 Ph_WM_CLOSE | Ph_WM_RESIZE | Ph_WM_FOCUS ); 1141 PtSetArg( &args[ n++ ], Pt_ARG_DIM, &window_size, 0 ); 1142 gui.vimWindow = PtCreateWidget( PtWindow, NULL, n, args ); 1143 if( gui.vimWindow == NULL ) 1144 return( FAIL ); 1145 1146 PtAddCallback( gui.vimWindow, Pt_CB_WINDOW, gui_ph_handle_window_cb, NULL ); 1147 PtAddCallback( gui.vimWindow, Pt_CB_WINDOW_OPENING, 1148 gui_ph_handle_window_open, NULL ); 1149 1150 n = 0; 1151 PtSetArg( &args[ n++ ], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_ALL, Pt_IS_ANCHORED ); 1152 PtSetArg( &args[ n++ ], Pt_ARG_DIM, &window_size, 0 ); 1153 PtSetArg( &args[ n++ ], Pt_ARG_POS, &pos, 0 ); 1154 1155#ifdef USE_PANEL_GROUP 1156 /* Put in a temprary place holder title */ 1157 PtSetArg( &args[ n++ ], Pt_ARG_PG_PANEL_TITLES, &empty_title, 1 ); 1158 1159 gui.vimPanelGroup = PtCreateWidget( PtPanelGroup, gui.vimWindow, n, args ); 1160 if( gui.vimPanelGroup == NULL ) 1161 return( FAIL ); 1162 1163 PtAddCallback( gui.vimPanelGroup, Pt_CB_PG_PANEL_SWITCHING, 1164 gui_ph_handle_pg_change, NULL ); 1165#else 1166 /* Turn off all edge decorations */ 1167 PtSetArg( &args[ n++ ], Pt_ARG_BASIC_FLAGS, Pt_FALSE, Pt_ALL ); 1168 PtSetArg( &args[ n++ ], Pt_ARG_BEVEL_WIDTH, 0, 0 ); 1169 PtSetArg( &args[ n++ ], Pt_ARG_MARGIN_WIDTH, 0, 0 ); 1170 PtSetArg( &args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 0, 0 ); 1171 PtSetArg( &args[ n++ ], Pt_ARG_CONTAINER_FLAGS, Pt_TRUE, Pt_AUTO_EXTENT ); 1172 1173 gui.vimContainer = PtCreateWidget( PtPane, gui.vimWindow, n, args ); 1174 if( gui.vimContainer == NULL ) 1175 return( FAIL ); 1176 1177 PtAddCallback( gui.vimContainer, Pt_CB_RESIZE, gui_ph_pane_resize, NULL ); 1178#endif 1179 1180 /* Size for the text area is set in gui_mch_set_text_area_pos */ 1181 n = 0; 1182 1183 PtSetArg( &args[ n++ ], Pt_ARG_RAW_DRAW_F, gui_ph_handle_raw_draw, 1 ); 1184 PtSetArg( &args[ n++ ], Pt_ARG_BEVEL_WIDTH, GUI_PH_MARGIN, 0 ); 1185 /* 1186 * Using focus render also causes the whole widget to be redrawn 1187 * whenever it changes focus, which is very annoying :p 1188 */ 1189 PtSetArg( &args[ n++ ], Pt_ARG_FLAGS, Pt_TRUE, 1190 Pt_GETS_FOCUS | Pt_HIGHLIGHTED ); 1191#ifndef FEAT_MOUSESHAPE 1192 PtSetArg( &args[ n++ ], Pt_ARG_CURSOR_TYPE, GUI_PH_MOUSE_TYPE, 0 ); 1193 PtSetArg( &args[ n++ ], Pt_ARG_CURSOR_COLOR, gui_ph_mouse_color, 0 ); 1194#endif 1195 1196 gui.vimTextArea = PtCreateWidget( PtRaw, Pt_DFLT_PARENT, n, args ); 1197 if( gui.vimTextArea == NULL) 1198 return( FAIL ); 1199 1200 /* TODO: use PtAddEventHandlers instead? */ 1201 /* Not using Ph_EV_BUT_REPEAT because vim wouldn't use it anyway */ 1202 PtAddEventHandler( gui.vimTextArea, 1203 Ph_EV_BUT_PRESS | Ph_EV_BUT_RELEASE | Ph_EV_PTR_MOTION_BUTTON, 1204 gui_ph_handle_mouse, NULL ); 1205 PtAddEventHandler( gui.vimTextArea, Ph_EV_KEY, 1206 gui_ph_handle_keyboard, NULL ); 1207 PtAddCallback( gui.vimTextArea, Pt_CB_GOT_FOCUS, 1208 gui_ph_handle_focus, NULL ); 1209 PtAddCallback( gui.vimTextArea, Pt_CB_LOST_FOCUS, 1210 gui_ph_handle_focus, NULL ); 1211 1212 /* 1213 * Now that the text area widget has been created, set up the colours, 1214 * which wil call PtSetResource from gui_mch_new_colors 1215 */ 1216 1217 /* 1218 * Create the two timers, not as accurate as using the kernel timer 1219 * functions, but good enough 1220 */ 1221 gui_ph_timer_cursor = PtCreateWidget( PtTimer, gui.vimWindow, 0, NULL ); 1222 if( gui_ph_timer_cursor == NULL ) 1223 return( FAIL ); 1224 1225 gui_ph_timer_timeout = PtCreateWidget( PtTimer, gui.vimWindow, 0, NULL ); 1226 if( gui_ph_timer_timeout == NULL ) 1227 return( FAIL ); 1228 1229 PtAddCallback( gui_ph_timer_cursor, Pt_CB_TIMER_ACTIVATE, 1230 gui_ph_handle_timer_cursor, NULL); 1231 PtAddCallback( gui_ph_timer_timeout, Pt_CB_TIMER_ACTIVATE, 1232 gui_ph_handle_timer_timeout, NULL); 1233 1234#ifdef FEAT_MENU 1235 n = 0; 1236 PtSetArg( &args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0 ); 1237 PtSetArg( &args[ n++ ], Pt_ARG_ANCHOR_FLAGS, Pt_ANCHOR_LEFT_RIGHT, 1238 Pt_IS_ANCHORED ); 1239 gui.vimToolBarGroup = PtCreateWidget( PtToolbarGroup, gui.vimWindow, 1240 n, args ); 1241 if( gui.vimToolBarGroup == NULL ) 1242 return( FAIL ); 1243 1244 PtAddCallback( gui.vimToolBarGroup, Pt_CB_RESIZE, 1245 gui_ph_handle_menu_resize, NULL ); 1246 1247 n = 0; 1248 flags = 0; 1249 PtSetArg( &args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0 ); 1250 if( ! vim_strchr( p_go, GO_MENUS ) ) 1251 { 1252 flags |= Pt_DELAY_REALIZE; 1253 PtSetArg( &args[ n++ ], Pt_ARG_FLAGS, Pt_TRUE, flags ); 1254 } 1255 gui.vimMenuBar = PtCreateWidget( PtMenuBar, gui.vimToolBarGroup, n, args ); 1256 if( gui.vimMenuBar == NULL ) 1257 return( FAIL ); 1258 1259# ifdef FEAT_TOOLBAR 1260 n = 0; 1261 1262 PtSetArg( &args[ n++ ], Pt_ARG_ANCHOR_FLAGS, 1263 Pt_ANCHOR_LEFT_RIGHT |Pt_TOP_ANCHORED_TOP, Pt_IS_ANCHORED ); 1264 PtSetArg( &args[ n++ ], Pt_ARG_RESIZE_FLAGS, Pt_TRUE, 1265 Pt_RESIZE_Y_AS_REQUIRED ); 1266 PtSetArg( &args[ n++ ], Pt_ARG_WIDTH, window_size.w, 0 ); 1267 1268 flags = Pt_GETS_FOCUS; 1269 if( ! vim_strchr( p_go, GO_TOOLBAR ) ) 1270 flags |= Pt_DELAY_REALIZE; 1271 1272 PtSetArg( &args[ n++ ], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, flags ); 1273 1274 gui.vimToolBar = PtCreateWidget( PtToolbar, gui.vimToolBarGroup, n, args ); 1275 if( gui.vimToolBar == NULL ) 1276 return( FAIL ); 1277 1278 /* 1279 * Size for the toolbar is fetched in gui_mch_show_toolbar, after 1280 * the buttons have been added and the toolbar has resized it's height 1281 * for the buttons to fit 1282 */ 1283# endif 1284 1285#endif 1286 1287 return( OK ); 1288} 1289 1290 int 1291gui_mch_init_check(void) 1292{ 1293 return( (is_photon_available == TRUE) ? OK : FAIL ); 1294} 1295 1296 int 1297gui_mch_open(void) 1298{ 1299 gui.norm_pixel = Pg_BLACK; 1300 gui.back_pixel = Pg_WHITE; 1301 1302 set_normal_colors(); 1303 1304 gui_check_colors(); 1305 gui.def_norm_pixel = gui.norm_pixel; 1306 gui.def_back_pixel = gui.back_pixel; 1307 1308 highlight_gui_started(); 1309 1310 if (gui_win_x != -1 && gui_win_y != -1) 1311 gui_mch_set_winpos(gui_win_x, gui_win_y); 1312 1313 return( (PtRealizeWidget( gui.vimWindow ) == 0) ? OK : FAIL ); 1314} 1315 1316 void 1317gui_mch_exit(int rc) 1318{ 1319 PtDestroyWidget( gui.vimWindow ); 1320 1321 PxTranslateSet( charset_translate, NULL ); 1322 1323 vim_free( gui.event_buffer ); 1324 1325#ifdef USE_PANEL_GROUPS 1326 vim_free( panel_titles ); 1327#endif 1328} 1329 1330/****************************************************************************/ 1331/* events */ 1332 1333/* When no events are available, photon will call this function, working is 1334 * set to FALSE, and the gui_mch_update loop will exit. */ 1335 static int 1336exit_gui_mch_update( void *data ) 1337{ 1338 *(int *)data = FALSE; 1339 return( Pt_END ); 1340} 1341 1342 void 1343gui_mch_update(void) 1344{ 1345 int working = TRUE; 1346 1347 PtAppAddWorkProc( NULL, exit_gui_mch_update, &working ); 1348 while( ( working == TRUE ) && !vim_is_input_buf_full()) 1349 { 1350 PtProcessEvent(); 1351 } 1352} 1353 1354 int 1355gui_mch_wait_for_chars(int wtime) 1356{ 1357 is_timeout = FALSE; 1358 1359 if( wtime > 0 ) 1360 PtSetResource( gui_ph_timer_timeout, Pt_ARG_TIMER_INITIAL, wtime, 0 ); 1361 1362 while( 1 ) 1363 { 1364 PtProcessEvent(); 1365 if( input_available() ) 1366 { 1367 PtSetResource( gui_ph_timer_timeout, Pt_ARG_TIMER_INITIAL, 0, 0 ); 1368 return( OK ); 1369 } 1370 else if( is_timeout == TRUE ) 1371 return( FAIL ); 1372 } 1373} 1374 1375#if defined( FEAT_BROWSE ) || defined( PROTO ) 1376/* 1377 * Put up a file requester. 1378 * Returns the selected name in allocated memory, or NULL for Cancel. 1379 * saving, select file to write 1380 * title title for the window 1381 * default_name default name (well duh!) 1382 * ext not used (extension added) 1383 * initdir initial directory, NULL for current dir 1384 * filter not used (file name filter) 1385 */ 1386 char_u * 1387gui_mch_browse( 1388 int saving, 1389 char_u *title, 1390 char_u *default_name, 1391 char_u *ext, 1392 char_u *initdir, 1393 char_u *filter) 1394{ 1395 PtFileSelectionInfo_t file; 1396 int flags; 1397 char_u *default_path; 1398 char_u *open_text = NULL; 1399 1400 flags = 0; 1401 memset( &file, 0, sizeof( file ) ); 1402 1403 default_path = alloc( MAXPATHL + 1 + NAME_MAX + 1 ); 1404 if( default_path != NULL ) 1405 { 1406 if( saving == TRUE ) 1407 { 1408 /* Don't need Pt_FSR_CONFIRM_EXISTING, vim will ask anyway */ 1409 flags |= Pt_FSR_NO_FCHECK; 1410 open_text = "&Save"; 1411 } 1412 1413 /* combine the directory and filename into a single path */ 1414 if( initdir == NULL || *initdir == NUL ) 1415 { 1416 mch_dirname( default_path, MAXPATHL ); 1417 initdir = default_path; 1418 } 1419 else 1420 { 1421 STRCPY( default_path, initdir ); 1422 initdir = default_path; 1423 } 1424 1425 if( default_name != NULL ) 1426 { 1427 if( default_path[ STRLEN( default_path ) - 1 ] != '/' ) 1428 STRCAT( default_path, "/" ); 1429 1430 STRCAT( default_path, default_name ); 1431 } 1432 1433 /* TODO: add a filter? */ 1434 PtFileSelection( 1435 gui.vimWindow, 1436 NULL, 1437 title, 1438 default_path, 1439 NULL, 1440 open_text, 1441 NULL, 1442 NULL, 1443 &file, 1444 flags ); 1445 1446 vim_free( default_path ); 1447 1448 if( file.ret == Pt_FSDIALOG_BTN1 ) 1449 return( vim_strsave( file.path ) ); 1450 } 1451 return( NULL ); 1452} 1453#endif 1454 1455#if defined( FEAT_GUI_DIALOG ) || defined( PROTO ) 1456static PtWidget_t *gui_ph_dialog_text = NULL; 1457 1458 static int 1459gui_ph_dialog_close( int button, void *data ) 1460{ 1461 PtModalCtrl_t *modal_ctrl = data; 1462 char_u *dialog_text, *vim_text; 1463 1464 if( gui_ph_dialog_text != NULL ) 1465 { 1466 PtGetResource( gui_ph_dialog_text, Pt_ARG_TEXT_STRING, &dialog_text, 0 ); 1467 PtGetResource( gui_ph_dialog_text, Pt_ARG_POINTER, &vim_text, 0 ); 1468 STRNCPY( vim_text, dialog_text, IOSIZE - 1 ); 1469 } 1470 1471 PtModalUnblock( modal_ctrl, (void *) button ); 1472 1473 return( Pt_TRUE ); 1474} 1475 1476 static int 1477gui_ph_dialog_text_enter( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 1478{ 1479 if( info->reason_subtype == Pt_EDIT_ACTIVATE ) 1480 gui_ph_dialog_close( 1, data ); 1481 return( Pt_CONTINUE ); 1482} 1483 1484 static int 1485gui_ph_dialog_esc( PtWidget_t *widget, void *data, PtCallbackInfo_t *info ) 1486{ 1487 PhKeyEvent_t *key; 1488 1489 key = PhGetData( info->event ); 1490 if( ( key->key_flags & Pk_KF_Cap_Valid ) && ( key->key_cap == Pk_Escape ) ) 1491 { 1492 gui_ph_dialog_close( 0, data ); 1493 return( Pt_CONSUME ); 1494 } 1495 return( Pt_PROCESS ); 1496} 1497 1498 int 1499gui_mch_dialog( 1500 int type, 1501 char_u *title, 1502 char_u *message, 1503 char_u *buttons, 1504 int default_button, 1505 char_u *textfield) 1506{ 1507 char_u *str; 1508 char_u **button_array; 1509 char_u *buttons_copy; 1510 1511 int button_count; 1512 int i, len; 1513 int dialog_result = -1; 1514 1515 /* FIXME: the vertical option in guioptions is blatantly ignored */ 1516 /* FIXME: so is the type */ 1517 1518 button_count = len = i = 0; 1519 1520 if( buttons == NULL || *buttons == NUL ) 1521 return( -1 ); 1522 1523 /* There is one less separator than buttons, so bump up the button count */ 1524 button_count = 1; 1525 1526 /* Count string length and number of seperators */ 1527 for( str = buttons; *str; str++ ) 1528 { 1529 len++; 1530 if( *str == DLG_BUTTON_SEP ) 1531 button_count++; 1532 } 1533 1534 if ( title == NULL ) 1535 title = "Vim"; 1536 1537 buttons_copy = alloc( len + 1 ); 1538 button_array = (char_u **) alloc( button_count * sizeof( char_u * ) ); 1539 if( buttons_copy != NULL && button_array != NULL ) 1540 { 1541 STRCPY( buttons_copy, buttons ); 1542 1543 /* 1544 * Convert DLG_BUTTON_SEP into NUL's and fill in 1545 * button_array with the pointer to each NUL terminated string 1546 */ 1547 str = buttons_copy; 1548 for( i = 0; i < button_count; i++ ) 1549 { 1550 button_array[ i ] = str; 1551 for( ; *str; str++ ) 1552 { 1553 if( *str == DLG_BUTTON_SEP ) 1554 { 1555 *str++ = NUL; 1556 break; 1557 } 1558 } 1559 } 1560#ifndef FEAT_GUI_TEXTDIALOG 1561 dialog_result = PtAlert( 1562 gui.vimWindow, NULL, 1563 title, 1564 NULL, 1565 message, NULL, 1566 button_count, (const char **) button_array, NULL, 1567 default_button, 0, Pt_MODAL ); 1568#else 1569 /* Writing the dialog ourselves lets us add extra features, like 1570 * trapping the escape key and returning 0 to vim */ 1571 { 1572 int n; 1573 PtArg_t args[5]; 1574 PtWidget_t *dialog, *pane; 1575 PtModalCtrl_t modal_ctrl; 1576 PtDialogInfo_t di; 1577 1578 memset( &di, 0, sizeof( di ) ); 1579 memset( &modal_ctrl, 0, sizeof( modal_ctrl ) ); 1580 1581 n = 0; 1582 PtSetArg( &args[n++], Pt_ARG_GROUP_ROWS_COLS, 0, 0 ); 1583 PtSetArg( &args[n++], Pt_ARG_WIDTH, 350, 0 ); 1584 PtSetArg( &args[n++], Pt_ARG_GROUP_ORIENTATION, 1585 Pt_GROUP_VERTICAL, 0 ); 1586 PtSetArg( &args[n++], Pt_ARG_GROUP_FLAGS, 1587 Pt_TRUE, Pt_GROUP_NO_KEYS | Pt_GROUP_STRETCH_HORIZONTAL ); 1588 PtSetArg( &args[n++], Pt_ARG_CONTAINER_FLAGS, Pt_FALSE, Pt_TRUE ); 1589 pane = PtCreateWidget( PtGroup, NULL, n, args ); 1590 1591 n = 0; 1592 PtSetArg( &args[n++], Pt_ARG_TEXT_STRING, message, 0 ); 1593 PtCreateWidget( PtLabel, pane, n, args ); 1594 1595 if( textfield != NULL ) 1596 { 1597 n = 0; 1598 PtSetArg( &args[n++], Pt_ARG_MAX_LENGTH, IOSIZE - 1, 0 ); 1599 PtSetArg( &args[n++], Pt_ARG_TEXT_STRING, textfield, 0 ); 1600 PtSetArg( &args[n++], Pt_ARG_POINTER, textfield, 0 ); 1601 gui_ph_dialog_text = PtCreateWidget( PtText, pane, n, args ); 1602 PtAddCallback( gui_ph_dialog_text, Pt_CB_ACTIVATE, 1603 gui_ph_dialog_text_enter, &modal_ctrl ); 1604 } 1605 1606 di.parent = gui.vimWindow; 1607 di.pane = pane; 1608 di.title = title; 1609 di.buttons = (const char **) button_array; 1610 di.nbtns = button_count; 1611 di.def_btn = default_button; 1612 /* This is just to give the dialog the close button. 1613 * We check for the Escape key ourselves and return 0 */ 1614 di.esc_btn = button_count; 1615 di.callback = gui_ph_dialog_close; 1616 di.data = &modal_ctrl; 1617 1618 dialog = PtCreateDialog( &di ); 1619 PtAddFilterCallback( dialog, Ph_EV_KEY, 1620 gui_ph_dialog_esc, &modal_ctrl ); 1621 1622 if( gui_ph_dialog_text != NULL ) 1623 PtGiveFocus( gui_ph_dialog_text, NULL ); 1624 1625 /* Open dialog, block the vim window and wait for the dialog to close */ 1626 PtRealizeWidget( dialog ); 1627 PtMakeModal( dialog, Ph_CURSOR_NOINPUT, Ph_CURSOR_DEFAULT_COLOR ); 1628 dialog_result = (int) PtModalBlock( &modal_ctrl, 0 ); 1629 1630 PtDestroyWidget( dialog ); 1631 gui_ph_dialog_text = NULL; 1632 } 1633#endif 1634 } 1635 1636 vim_free( button_array ); 1637 vim_free( buttons_copy ); 1638 1639 return( dialog_result ); 1640} 1641#endif 1642/****************************************************************************/ 1643/* window size/position/state */ 1644 1645 int 1646gui_mch_get_winpos(int *x, int *y) 1647{ 1648 PhPoint_t *pos; 1649 1650 pos = PtWidgetPos( gui.vimWindow, NULL ); 1651 1652 *x = pos->x; 1653 *y = pos->y; 1654 1655 return( OK ); 1656} 1657 1658 void 1659gui_mch_set_winpos(int x, int y) 1660{ 1661 PhPoint_t pos = { x, y }; 1662 1663 PtSetResource( gui.vimWindow, Pt_ARG_POS, &pos, 0 ); 1664} 1665 1666 void 1667gui_mch_set_shellsize(int width, int height, 1668 int min_width, int min_height, int base_width, int base_height, 1669 int direction) 1670{ 1671 PhDim_t window_size = { width, height }; 1672 PhDim_t min_size = { min_width, min_height }; 1673 1674#ifdef USE_PANEL_GROUP 1675 window_size.w += pg_margin_left + pg_margin_right; 1676 window_size.h += pg_margin_top + pg_margin_bottom; 1677#endif 1678 1679 PtSetResource( gui.vimWindow, Pt_ARG_MINIMUM_DIM, &min_size, 0 ); 1680 PtSetResource( gui.vimWindow, Pt_ARG_DIM, &window_size, 0 ); 1681 1682 if( ! PtWidgetIsRealized( gui.vimWindow ) ) 1683 gui_ph_resize_container(); 1684} 1685 1686/* 1687 * Return the amount of screen space that hasn't been allocated (such as 1688 * by the shelf). 1689 */ 1690 void 1691gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) 1692{ 1693 PhRect_t console; 1694 1695 PhWindowQueryVisible( Ph_QUERY_WORKSPACE, 0, 1696 PhInputGroup( NULL ), &console ); 1697 1698 *screen_w = console.lr.x - console.ul.x + 1; 1699 *screen_h = console.lr.y - console.ul.y + 1; 1700} 1701 1702 void 1703gui_mch_iconify(void) 1704{ 1705 PhWindowEvent_t event; 1706 1707 memset( &event, 0, sizeof (event) ); 1708 event.event_f = Ph_WM_HIDE; 1709 event.event_state = Ph_WM_EVSTATE_HIDE; 1710 event.rid = PtWidgetRid( gui.vimWindow ); 1711 PtForwardWindowEvent( &event ); 1712} 1713 1714#if defined(FEAT_EVAL) || defined(PROTO) 1715/* 1716 * Bring the Vim window to the foreground. 1717 */ 1718 void 1719gui_mch_set_foreground() 1720{ 1721 PhWindowEvent_t event; 1722 1723 memset( &event, 0, sizeof (event) ); 1724 event.event_f = Ph_WM_TOFRONT; 1725 event.event_state = Ph_WM_EVSTATE_FFRONT; 1726 event.rid = PtWidgetRid( gui.vimWindow ); 1727 PtForwardWindowEvent( &event ); 1728} 1729#endif 1730 1731 void 1732gui_mch_settitle(char_u *title, char_u *icon) 1733{ 1734#ifdef USE_PANEL_GROUP 1735 gui_ph_pg_set_buffer_num( curwin->w_buffer->b_fnum ); 1736#endif 1737 PtSetResource( gui.vimWindow, Pt_ARG_WINDOW_TITLE, title, 0 ); 1738 /* Not sure what to do with the icon text, set balloon text somehow? */ 1739} 1740 1741/****************************************************************************/ 1742/* Scrollbar */ 1743 1744 void 1745gui_mch_set_scrollbar_thumb(scrollbar_T *sb, int val, int size, int max) 1746{ 1747 int n = 0; 1748 PtArg_t args[3]; 1749 1750 PtSetArg( &args[ n++ ], Pt_ARG_MAXIMUM, max, 0 ); 1751 PtSetArg( &args[ n++ ], Pt_ARG_SLIDER_SIZE, size, 0 ); 1752 PtSetArg( &args[ n++ ], Pt_ARG_GAUGE_VALUE, val, 0 ); 1753 PtSetResources( sb->id, n, args ); 1754} 1755 1756 void 1757gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h) 1758{ 1759 PhArea_t area = {{ x, y }, { w, h }}; 1760 1761 PtSetResource( sb->id, Pt_ARG_AREA, &area, 0 ); 1762} 1763 1764 void 1765gui_mch_create_scrollbar(scrollbar_T *sb, int orient) 1766{ 1767 int n = 0; 1768/* int anchor_flags = 0;*/ 1769 PtArg_t args[4]; 1770 1771 /* 1772 * Stop the scrollbar from being realized when the parent 1773 * is realized, so it can be explicitly realized by vim. 1774 * 1775 * Also, don't let the scrollbar get focus 1776 */ 1777 PtSetArg( &args[ n++ ], Pt_ARG_FLAGS, Pt_DELAY_REALIZE, 1778 Pt_DELAY_REALIZE | Pt_GETS_FOCUS ); 1779 PtSetArg( &args[ n++ ], Pt_ARG_SCROLLBAR_FLAGS, Pt_SCROLLBAR_SHOW_ARROWS, 0); 1780#if 0 1781 /* Don't need this anchoring for the scrollbars */ 1782 if( orient == SBAR_HORIZ ) 1783 { 1784 anchor_flags = Pt_BOTTOM_ANCHORED_BOTTOM | 1785 Pt_LEFT_ANCHORED_LEFT | Pt_RIGHT_ANCHORED_RIGHT; 1786 } 1787 else 1788 { 1789 anchor_flags = Pt_BOTTOM_ANCHORED_BOTTOM | Pt_TOP_ANCHORED_TOP; 1790 if( sb->wp != NULL ) 1791 { 1792 if( sb == &sb->wp->w_scrollbars[ SBAR_LEFT ] ) 1793 anchor_flags |= Pt_LEFT_ANCHORED_LEFT; 1794 else 1795 anchor_flags |= Pt_RIGHT_ANCHORED_RIGHT; 1796 } 1797 } 1798 PtSetArg( &args[ n++ ], Pt_ARG_ANCHOR_FLAGS, anchor_flags, Pt_IS_ANCHORED ); 1799#endif 1800 PtSetArg( &args[ n++ ], Pt_ARG_ORIENTATION, 1801 (orient == SBAR_HORIZ) ? Pt_HORIZONTAL : Pt_VERTICAL, 0 ); 1802#ifdef USE_PANEL_GROUP 1803 sb->id = PtCreateWidget( PtScrollbar, gui.vimPanelGroup, n, args ); 1804#else 1805 sb->id = PtCreateWidget( PtScrollbar, gui.vimContainer, n, args ); 1806#endif 1807 1808 PtAddCallback( sb->id, Pt_CB_SCROLLBAR_MOVE, gui_ph_handle_scrollbar, sb ); 1809} 1810 1811 void 1812gui_mch_enable_scrollbar(scrollbar_T *sb, int flag) 1813{ 1814 if( flag != 0 ) 1815 PtRealizeWidget( sb->id ); 1816 else 1817 PtUnrealizeWidget( sb->id ); 1818} 1819 1820 void 1821gui_mch_destroy_scrollbar(scrollbar_T *sb) 1822{ 1823 PtDestroyWidget( sb->id ); 1824 sb->id = NULL; 1825} 1826 1827/****************************************************************************/ 1828/* Mouse functions */ 1829 1830#if defined(FEAT_MOUSESHAPE) || defined(PROTO) 1831/* The last set mouse pointer shape is remembered, to be used when it goes 1832 * from hidden to not hidden. */ 1833static int last_shape = 0; 1834 1835/* Table for shape IDs. Keep in sync with the mshape_names[] table in 1836 * misc2.c! */ 1837static int mshape_ids[] = 1838{ 1839 Ph_CURSOR_POINTER, /* arrow */ 1840 Ph_CURSOR_NONE, /* blank */ 1841 Ph_CURSOR_INSERT, /* beam */ 1842 Ph_CURSOR_DRAG_VERTICAL, /* updown */ 1843 Ph_CURSOR_DRAG_VERTICAL, /* udsizing */ 1844 Ph_CURSOR_DRAG_HORIZONTAL, /* leftright */ 1845 Ph_CURSOR_DRAG_HORIZONTAL, /* lrsizing */ 1846 Ph_CURSOR_WAIT, /* busy */ 1847 Ph_CURSOR_DONT, /* no */ 1848 Ph_CURSOR_CROSSHAIR, /* crosshair */ 1849 Ph_CURSOR_FINGER, /* hand1 */ 1850 Ph_CURSOR_FINGER, /* hand2 */ 1851 Ph_CURSOR_FINGER, /* pencil */ 1852 Ph_CURSOR_QUESTION_POINT, /* question */ 1853 Ph_CURSOR_POINTER, /* right-arrow */ 1854 Ph_CURSOR_POINTER, /* up-arrow */ 1855 Ph_CURSOR_POINTER /* last one */ 1856}; 1857 1858 void 1859mch_set_mouse_shape(shape) 1860 int shape; 1861{ 1862 int id; 1863 1864 if (!gui.in_use) 1865 return; 1866 1867 if (shape == MSHAPE_HIDE || gui.pointer_hidden) 1868 PtSetResource( gui.vimTextArea, Pt_ARG_CURSOR_TYPE, Ph_CURSOR_NONE, 1869 0 ); 1870 else 1871 { 1872 if (shape >= MSHAPE_NUMBERED) 1873 id = Ph_CURSOR_POINTER; 1874 else 1875 id = mshape_ids[shape]; 1876 1877 PtSetResource( gui.vimTextArea, Pt_ARG_CURSOR_TYPE, id, 0 ); 1878 } 1879 if (shape != MSHAPE_HIDE) 1880 last_shape = shape; 1881} 1882#endif 1883 1884 void 1885gui_mch_mousehide(int hide) 1886{ 1887 if( gui.pointer_hidden != hide ) 1888 { 1889 gui.pointer_hidden = hide; 1890#ifdef FEAT_MOUSESHAPE 1891 if( hide ) 1892 PtSetResource( gui.vimTextArea, Pt_ARG_CURSOR_TYPE, 1893 Ph_CURSOR_NONE, 0 ); 1894 else 1895 mch_set_mouse_shape( last_shape ); 1896#else 1897 PtSetResource( gui.vimTextArea, Pt_ARG_CURSOR_TYPE, 1898 ( hide == MOUSE_SHOW ) ? GUI_PH_MOUSE_TYPE : Ph_CURSOR_NONE, 1899 0 ); 1900#endif 1901 } 1902} 1903 1904 void 1905gui_mch_getmouse(int *x, int *y) 1906{ 1907 PhCursorInfo_t info; 1908 short ix, iy; 1909 1910 /* FIXME: does this return the correct position, 1911 * with respect to the border? */ 1912 PhQueryCursor( PhInputGroup( NULL ), &info ); 1913 PtGetAbsPosition( gui.vimTextArea , &ix, &iy ); 1914 1915 *x = info.pos.x - ix; 1916 *y = info.pos.y - iy; 1917} 1918 1919 void 1920gui_mch_setmouse(int x, int y) 1921{ 1922 short abs_x, abs_y; 1923 1924 PtGetAbsPosition( gui.vimTextArea, &abs_x, &abs_y ); 1925 /* Add the border offset? */ 1926 PhMoveCursorAbs( PhInputGroup( NULL ), abs_x + x, abs_y + y ); 1927} 1928 1929/****************************************************************************/ 1930/* Colours */ 1931 1932/* 1933 * Return the RGB value of a pixel as a long. 1934 */ 1935 long_u 1936gui_mch_get_rgb(guicolor_T pixel) 1937{ 1938 return PgRGB(PgRedValue(pixel), PgGreenValue(pixel), PgBlueValue(pixel)); 1939} 1940 1941 void 1942gui_mch_new_colors(void) 1943{ 1944#if 0 /* Don't bother changing the cursor colour */ 1945 short color_diff; 1946 1947 /* 1948 * If there isn't enough difference between the background colour and 1949 * the mouse pointer colour then change the mouse pointer colour 1950 */ 1951 color_diff = gui_get_lightness(gui_ph_mouse_color) 1952 - gui_get_lightness(gui.back_pixel); 1953 1954 if( abs( color_diff ) < 64 ) 1955 { 1956 short r, g, b; 1957 /* not a great algorithm... */ 1958 r = PgRedValue( gui_ph_mouse_color ) ^ 255; 1959 g = PgGreenValue( gui_ph_mouse_color ) ^ 255; 1960 b = PgBlueValue( gui_ph_mouse_color ) ^ 255; 1961 1962#ifndef FEAT_MOUSESHAPE 1963 gui_ph_mouse_color = PgRGB( r, g, b ); 1964 PtSetResource( gui.vimTextArea, Pt_ARG_CURSOR_COLOR, 1965 gui_ph_mouse_color, 0 ); 1966#endif 1967 } 1968#endif 1969 1970 PtSetResource( gui.vimTextArea, Pt_ARG_FILL_COLOR, gui.back_pixel, 0 ); 1971} 1972 1973 static int 1974hex_digit(int c) 1975{ 1976 if (VIM_ISDIGIT(c)) 1977 return( c - '0' ); 1978 c = TOLOWER_ASC(c); 1979 if (c >= 'a' && c <= 'f') 1980 return( c - 'a' + 10 ); 1981 return( -1000 ); 1982} 1983 1984 1985/* 1986 * This should be split out into a separate file, 1987 * every port does basically the same thing. 1988 * 1989 * This is the gui_w32.c version (i think..) 1990 * Return INVALCOLOR when failed. 1991 */ 1992 1993 guicolor_T 1994gui_mch_get_color(char_u *name) 1995{ 1996 int i; 1997 int r, g, b; 1998 1999 2000 typedef struct GuiColourTable 2001 { 2002 char *name; 2003 guicolor_T colour; 2004 } GuiColourTable; 2005 2006 static GuiColourTable table[] = 2007 { 2008 {"Black", RGB(0x00, 0x00, 0x00)}, 2009 {"DarkGray", RGB(0x80, 0x80, 0x80)}, 2010 {"DarkGrey", RGB(0x80, 0x80, 0x80)}, 2011 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, 2012 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, 2013 {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, 2014 {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, 2015 {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, 2016 {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, 2017 {"Gray20", RGB(0x33, 0x33, 0x33)}, 2018 {"Grey20", RGB(0x33, 0x33, 0x33)}, 2019 {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, 2020 {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, 2021 {"Gray40", RGB(0x66, 0x66, 0x66)}, 2022 {"Grey40", RGB(0x66, 0x66, 0x66)}, 2023 {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, 2024 {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, 2025 {"Gray60", RGB(0x99, 0x99, 0x99)}, 2026 {"Grey60", RGB(0x99, 0x99, 0x99)}, 2027 {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, 2028 {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, 2029 {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, 2030 {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, 2031 {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, 2032 {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, 2033 {"White", RGB(0xFF, 0xFF, 0xFF)}, 2034 {"DarkRed", RGB(0x80, 0x00, 0x00)}, 2035 {"Red", RGB(0xFF, 0x00, 0x00)}, 2036 {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, 2037 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, 2038 {"Blue", RGB(0x00, 0x00, 0xFF)}, 2039 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)}, 2040 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, 2041 {"Green", RGB(0x00, 0xFF, 0x00)}, 2042 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)}, 2043 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, 2044 {"Cyan", RGB(0x00, 0xFF, 0xFF)}, 2045 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)}, 2046 {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, 2047 {"Magenta", RGB(0xFF, 0x00, 0xFF)}, 2048 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, 2049 {"Brown", RGB(0x80, 0x40, 0x40)}, 2050 {"Yellow", RGB(0xFF, 0xFF, 0x00)}, 2051 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)}, 2052 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, 2053 {"Orange", RGB(0xFF, 0xA5, 0x00)}, 2054 {"Purple", RGB(0xA0, 0x20, 0xF0)}, 2055 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, 2056 {"Violet", RGB(0xEE, 0x82, 0xEE)}, 2057 }; 2058 2059 /* is name #rrggbb format? */ 2060 if( name[0] == '#' && STRLEN( name ) == 7 ) 2061 { 2062 r = hex_digit( name[1] ) * 16 + hex_digit( name[2] ); 2063 g = hex_digit( name[3] ) * 16 + hex_digit( name[4] ); 2064 b = hex_digit( name[5] ) * 16 + hex_digit( name[6] ); 2065 if( r < 0 || g < 0 || b < 0 ) 2066 return INVALCOLOR; 2067 return( RGB( r, g, b ) ); 2068 } 2069 2070 for( i = 0; i < ARRAY_LENGTH( table ); i++ ) 2071 { 2072 if( STRICMP( name, table[i].name ) == 0 ) 2073 return( table[i].colour ); 2074 } 2075 2076 /* 2077 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". 2078 */ 2079 { 2080#define LINE_LEN 100 2081 FILE *fd; 2082 char line[LINE_LEN]; 2083 char_u *fname; 2084 2085 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); 2086 if (fname == NULL) 2087 return INVALCOLOR; 2088 2089 fd = fopen((char *)fname, "rt"); 2090 vim_free(fname); 2091 if (fd == NULL) 2092 return INVALCOLOR; 2093 2094 while (!feof(fd)) 2095 { 2096 int len; 2097 int pos; 2098 char *color; 2099 2100 fgets(line, LINE_LEN, fd); 2101 len = STRLEN(line); 2102 2103 if (len <= 1 || line[len-1] != '\n') 2104 continue; 2105 2106 line[len-1] = '\0'; 2107 2108 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); 2109 if (i != 3) 2110 continue; 2111 2112 color = line + pos; 2113 2114 if (STRICMP(color, name) == 0) 2115 { 2116 fclose(fd); 2117 return( (guicolor_T) RGB(r,g,b) ); 2118 } 2119 } 2120 2121 fclose(fd); 2122 } 2123 2124 2125 return INVALCOLOR; 2126} 2127 2128 void 2129gui_mch_set_fg_color(guicolor_T color) 2130{ 2131 PgSetTextColor( color ); 2132} 2133 2134 void 2135gui_mch_set_bg_color(guicolor_T color) 2136{ 2137 PgSetFillColor( color ); 2138} 2139 2140 void 2141gui_mch_set_sp_color(guicolor_T color) 2142{ 2143} 2144 2145 void 2146gui_mch_invert_rectangle(int row, int col, int nr, int nc) 2147{ 2148 PhRect_t rect; 2149 2150 rect.ul.x = FILL_X( col ); 2151 rect.ul.y = FILL_Y( row ); 2152 2153 /* FIXME: This has an off by one pixel problem */ 2154 rect.lr.x = rect.ul.x + nc * gui.char_width; 2155 rect.lr.y = rect.ul.y + nr * gui.char_height; 2156 if( nc > 0 ) 2157 rect.lr.x -= 1; 2158 if( nr > 0 ) 2159 rect.lr.y -= 1; 2160 2161 DRAW_START; 2162 PgSetDrawMode( Pg_DrawModeDSTINVERT ); 2163 PgDrawRect( &rect, Pg_DRAW_FILL ); 2164 PgSetDrawMode( Pg_DrawModeSRCCOPY ); 2165 DRAW_END; 2166} 2167 2168 void 2169gui_mch_clear_block(int row1, int col1, int row2, int col2) 2170{ 2171 PhRect_t block = { 2172 { FILL_X( col1 ), FILL_Y( row1 ) }, 2173 { FILL_X( col2 + 1 ) - 1, FILL_Y( row2 + 1 ) - 1} 2174 }; 2175 2176 DRAW_START; 2177 gui_mch_set_bg_color( gui.back_pixel ); 2178 PgDrawRect( &block, Pg_DRAW_FILL ); 2179 DRAW_END; 2180} 2181 2182 void 2183gui_mch_clear_all() 2184{ 2185 PhRect_t text_rect = { 2186 { gui.border_width, gui.border_width }, 2187 { Columns * gui.char_width + gui.border_width - 1 , 2188 Rows * gui.char_height + gui.border_width - 1 } 2189 }; 2190 2191 if( is_ignore_draw == TRUE ) 2192 return; 2193 2194 DRAW_START; 2195 gui_mch_set_bg_color( gui.back_pixel ); 2196 PgDrawRect( &text_rect, Pg_DRAW_FILL ); 2197 DRAW_END; 2198} 2199 2200 void 2201gui_mch_delete_lines(int row, int num_lines) 2202{ 2203 PhRect_t rect; 2204 PhPoint_t delta; 2205 2206 rect.ul.x = FILL_X( gui.scroll_region_left ); 2207 rect.ul.y = FILL_Y( row + num_lines ); 2208 2209 rect.lr.x = FILL_X( gui.scroll_region_right + 1 ) - 1; 2210 rect.lr.y = FILL_Y( gui.scroll_region_bot + 1) - 1; 2211 2212 PtWidgetOffset( gui.vimTextArea, &gui_ph_raw_offset ); 2213 PhTranslatePoint( &gui_ph_raw_offset, PtWidgetPos(gui.vimTextArea, NULL)); 2214 PhTranslateRect( &rect, &gui_ph_raw_offset ); 2215 2216 delta.x = 0; 2217 delta.y = -num_lines * gui.char_height; 2218 2219 PgFlush(); 2220 2221 PhBlit( PtWidgetRid( PtFindDisjoint( gui.vimTextArea ) ), &rect, &delta ); 2222 2223 gui_clear_block( 2224 gui.scroll_region_bot - num_lines + 1, 2225 gui.scroll_region_left, 2226 gui.scroll_region_bot, 2227 gui.scroll_region_right ); 2228} 2229 2230 void 2231gui_mch_insert_lines(int row, int num_lines) 2232{ 2233 PhRect_t rect; 2234 PhPoint_t delta; 2235 2236 rect.ul.x = FILL_X( gui.scroll_region_left ); 2237 rect.ul.y = FILL_Y( row ); 2238 2239 rect.lr.x = FILL_X( gui.scroll_region_right + 1 ) - 1; 2240 rect.lr.y = FILL_Y( gui.scroll_region_bot - num_lines + 1 ) - 1; 2241 2242 PtWidgetOffset( gui.vimTextArea, &gui_ph_raw_offset ); 2243 PhTranslatePoint( &gui_ph_raw_offset, PtWidgetPos( gui.vimTextArea, NULL ) ); 2244 PhTranslateRect( &rect, &gui_ph_raw_offset ); 2245 2246 delta.x = 0; 2247 delta.y = num_lines * gui.char_height; 2248 2249 PgFlush(); 2250 2251 PhBlit( PtWidgetRid( PtFindDisjoint( gui.vimTextArea ) ) , &rect, &delta ); 2252 2253 gui_clear_block( row, gui.scroll_region_left, 2254 row + num_lines - 1, gui.scroll_region_right ); 2255} 2256 2257 void 2258gui_mch_draw_string(int row, int col, char_u *s, int len, int flags) 2259{ 2260 static char *utf8_buffer = NULL; 2261 static int utf8_len = 0; 2262 2263 PhPoint_t pos = { TEXT_X( col ), TEXT_Y( row ) }; 2264 PhRect_t rect; 2265 2266 if( is_ignore_draw == TRUE ) 2267 return; 2268 2269 DRAW_START; 2270 2271 if( !( flags & DRAW_TRANSP ) ) 2272 { 2273 PgDrawIRect( 2274 FILL_X( col ), FILL_Y( row ), 2275 FILL_X( col + len ) - 1, FILL_Y( row + 1 ) - 1, 2276 Pg_DRAW_FILL ); 2277 } 2278 2279 if( flags & DRAW_UNDERL ) 2280 PgSetUnderline( gui.norm_pixel, Pg_TRANSPARENT, 0 ); 2281 2282 if( charset_translate != NULL 2283#ifdef FEAT_MBYTE 2284 && enc_utf8 == 0 2285#endif 2286 ) 2287 { 2288 int src_taken, dst_made; 2289 2290 /* Use a static buffer to avoid large amounts of de/allocations */ 2291 if( utf8_len < len ) 2292 { 2293 utf8_buffer = realloc( utf8_buffer, len * MB_LEN_MAX ); 2294 utf8_len = len; 2295 } 2296 2297 PxTranslateToUTF( 2298 charset_translate, 2299 s, 2300 len, 2301 &src_taken, 2302 utf8_buffer, 2303 utf8_len, 2304 &dst_made ); 2305 s = utf8_buffer; 2306 len = dst_made; 2307 } 2308 2309 PgDrawText( s, len, &pos, 0 ); 2310 2311 if( flags & DRAW_BOLD ) 2312 { 2313 /* FIXME: try and only calculate these values once... */ 2314 rect.ul.x = FILL_X( col ) + 1; 2315 rect.ul.y = FILL_Y( row ); 2316 rect.lr.x = FILL_X( col + len ) - 1; 2317 rect.lr.y = FILL_Y( row + 1) - 1; 2318 /* PgSetUserClip( NULL ) causes the scrollbar to not redraw... */ 2319#if 0 2320 pos.x++; 2321 2322 PgSetUserClip( &rect ); 2323 PgDrawText( s, len, &pos, 0 ); 2324 PgSetUserClip( NULL ); 2325#else 2326 rect.lr.y -= ( p_linespace + 1 ) / 2; 2327 /* XXX: DrawTextArea doesn't work with phditto */ 2328 PgDrawTextArea( s, len, &rect, Pg_TEXT_BOTTOM ); 2329#endif 2330 } 2331 2332 if( flags & DRAW_UNDERL ) 2333 PgSetUnderline( Pg_TRANSPARENT, Pg_TRANSPARENT, 0 ); 2334 2335 DRAW_END; 2336} 2337 2338/****************************************************************************/ 2339/* Cursor */ 2340 2341 void 2342gui_mch_draw_hollow_cursor(guicolor_T color) 2343{ 2344 PhRect_t r; 2345 2346 /* FIXME: Double width characters */ 2347 2348 r.ul.x = FILL_X( gui.col ); 2349 r.ul.y = FILL_Y( gui.row ); 2350 r.lr.x = r.ul.x + gui.char_width - 1; 2351 r.lr.y = r.ul.y + gui.char_height - 1; 2352 2353 DRAW_START; 2354 PgSetStrokeColor( color ); 2355 PgDrawRect( &r, Pg_DRAW_STROKE ); 2356 DRAW_END; 2357} 2358 2359 void 2360gui_mch_draw_part_cursor(int w, int h, guicolor_T color) 2361{ 2362 PhRect_t r; 2363 2364 r.ul.x = FILL_X( gui.col ); 2365 r.ul.y = FILL_Y( gui.row ) + gui.char_height - h; 2366 r.lr.x = r.ul.x + w - 1; 2367 r.lr.y = r.ul.y + h - 1; 2368 2369 DRAW_START; 2370 gui_mch_set_bg_color( color ); 2371 PgDrawRect( &r, Pg_DRAW_FILL ); 2372 DRAW_END; 2373} 2374 2375 void 2376gui_mch_set_blinking(long wait, long on, long off) 2377{ 2378 blink_waittime = wait; 2379 blink_ontime = on; 2380 blink_offtime = off; 2381} 2382 2383 void 2384gui_mch_start_blink(void) 2385{ 2386 /* Only turn on the timer on if none of the times are zero */ 2387 if( blink_waittime && blink_ontime && blink_offtime && gui.in_focus) 2388 { 2389 PtSetResource( gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 2390 blink_waittime, 0 ); 2391 blink_state = BLINK_ON; 2392 gui_update_cursor(TRUE, FALSE); 2393 } 2394} 2395 2396 void 2397gui_mch_stop_blink(void) 2398{ 2399 PtSetResource( gui_ph_timer_cursor, Pt_ARG_TIMER_INITIAL, 0, 0 ); 2400 2401 if( blink_state == BLINK_OFF ) 2402 gui_update_cursor(TRUE, FALSE); 2403 2404 blink_state = BLINK_NONE; 2405} 2406 2407/****************************************************************************/ 2408/* miscellaneous functions */ 2409 2410 void 2411gui_mch_beep(void) 2412{ 2413 PtBeep(); 2414} 2415 2416 void 2417gui_mch_flash(int msec) 2418{ 2419 PgSetFillXORColor( Pg_BLACK, Pg_WHITE ); 2420 PgSetDrawMode( Pg_DRAWMODE_XOR ); 2421 gui_mch_clear_all(); 2422 gui_mch_flush(); 2423 2424 ui_delay( (long) msec, TRUE ); 2425 2426 gui_mch_clear_all(); 2427 PgSetDrawMode( Pg_DRAWMODE_OPAQUE ); 2428 gui_mch_flush(); 2429} 2430 2431 void 2432gui_mch_flush(void) 2433{ 2434 PgFlush(); 2435} 2436 2437 void 2438gui_mch_set_text_area_pos(int x, int y, int w, int h) 2439{ 2440 PhArea_t area = {{x, y}, {w, h}}; 2441 2442 PtSetResource( gui.vimTextArea, Pt_ARG_AREA, &area, 0 ); 2443} 2444 2445 int 2446gui_mch_haskey(char_u *name) 2447{ 2448 int i; 2449 2450 for (i = 0; special_keys[i].key_sym != 0; i++) 2451 if (name[0] == special_keys[i].vim_code0 && 2452 name[1] == special_keys[i].vim_code1) 2453 return( OK ); 2454 return( FAIL ); 2455} 2456 2457/****************************************************************************/ 2458/* Menu */ 2459 2460#ifdef FEAT_TOOLBAR 2461#include "toolbar.phi" 2462 2463static PhImage_t *gui_ph_toolbar_images[] = { 2464 &tb_new_phi, 2465 &tb_open_phi, 2466 &tb_save_phi, 2467 &tb_undo_phi, 2468 &tb_redo_phi, 2469 &tb_cut_phi, 2470 &tb_copy_phi, 2471 &tb_paste_phi, 2472 &tb_print_phi, 2473 &tb_help_phi, 2474 &tb_find_phi, 2475 &tb_save_all_phi, 2476 &tb_save_session_phi, 2477 &tb_new_session_phi, 2478 &tb_load_session_phi, 2479 &tb_macro_phi, 2480 &tb_replace_phi, 2481 &tb_close_phi, 2482 &tb_maximize_phi, 2483 &tb_minimize_phi, 2484 &tb_split_phi, 2485 &tb_shell_phi, 2486 &tb_find_prev_phi, 2487 &tb_find_next_phi, 2488 &tb_find_help_phi, 2489 &tb_make_phi, 2490 &tb_jump_phi, 2491 &tb_ctags_phi, 2492 &tb_vsplit_phi, 2493 &tb_maxwidth_phi, 2494 &tb_minwidth_phi 2495}; 2496 2497static PhImage_t * 2498gui_ph_toolbar_load_icon( char_u *iconfile ) 2499{ 2500 static PhImage_t external_icon; 2501 PhImage_t *temp_phi = NULL; 2502 2503 temp_phi = PxLoadImage( iconfile, NULL ); 2504 if( temp_phi != NULL ) 2505 { 2506 /* The label widget will free the image/palette/etc. for us when 2507 * it's destroyed */ 2508 temp_phi->flags |= Ph_RELEASE_IMAGE_ALL; 2509 memcpy( &external_icon, temp_phi, sizeof( external_icon ) ); 2510 free( temp_phi ); 2511 2512 temp_phi = &external_icon; 2513 } 2514 return( temp_phi ); 2515} 2516 2517/* 2518 * This returns either a builtin icon image, an external image or NULL 2519 * if it can't find either. The caller can't and doesn't need to try and 2520 * free() the returned image, and it can't store the image pointer. 2521 * (When setting the Pt_ARG_LABEL_IMAGE resource, the contents of the 2522 * PhImage_t are copied, and the original PhImage_t aren't needed anymore). 2523 */ 2524static PhImage_t * 2525gui_ph_toolbar_find_icon( vimmenu_T *menu ) 2526{ 2527 char_u full_pathname[ MAXPATHL + 1 ]; 2528 PhImage_t *icon = NULL; 2529 2530 if( menu->icon_builtin == FALSE ) 2531 { 2532 if( menu->iconfile != NULL ) 2533 /* TODO: use gui_find_iconfile() */ 2534 icon = gui_ph_toolbar_load_icon( menu->iconfile ); 2535 2536 /* TODO: Restrict loading to just .png? Search for any format? */ 2537 if( ( icon == NULL ) && 2538 ( ( gui_find_bitmap( menu->name, full_pathname, "gif" ) == OK ) || 2539 ( gui_find_bitmap( menu->name, full_pathname, "png" ) == OK ) ) ) 2540 icon = gui_ph_toolbar_load_icon( full_pathname ); 2541 2542 if( icon != NULL ) 2543 return( icon ); 2544 } 2545 2546 if( menu->iconidx >= 0 && 2547 ( menu->iconidx < ARRAY_LENGTH( gui_ph_toolbar_images ) ) ) 2548 { 2549 return( gui_ph_toolbar_images[ menu->iconidx ] ); 2550 } 2551 2552 return( NULL ); 2553} 2554#endif 2555 2556#if defined( FEAT_MENU ) || defined( PROTO ) 2557 void 2558gui_mch_enable_menu(int flag) 2559{ 2560 if( flag != 0 ) 2561 PtRealizeWidget( gui.vimMenuBar ); 2562 else 2563 PtUnrealizeWidget( gui.vimMenuBar ); 2564} 2565 2566 void 2567gui_mch_set_menu_pos(int x, int y, int w, int h) 2568{ 2569 /* Nothing */ 2570} 2571 2572/* Change the position of a menu button in the parent */ 2573 static void 2574gui_ph_position_menu( PtWidget_t *widget, int priority ) 2575{ 2576 PtWidget_t *traverse; 2577 vimmenu_T *menu; 2578 2579 traverse = PtWidgetChildBack( PtWidgetParent( widget ) ); 2580 2581 /* Iterate through the list of widgets in traverse, until 2582 * we find the position we want to insert our widget into */ 2583 /* TODO: traverse from front to back, possible speedup? */ 2584 while( traverse != NULL ) 2585 { 2586 PtGetResource( traverse, Pt_ARG_POINTER, &menu, 0 ); 2587 2588 if( menu != NULL && 2589 priority < menu->priority && 2590 widget != traverse ) 2591 { 2592 /* Insert the widget before the current traverse widget */ 2593 PtWidgetInsert( widget, traverse, 1 ); 2594 return; 2595 } 2596 2597 traverse = PtWidgetBrotherInFront( traverse ); 2598 } 2599} 2600 2601/* the index is ignored because it's not useful for our purposes */ 2602 void 2603gui_mch_add_menu(vimmenu_T *menu, int index) 2604{ 2605 vimmenu_T *parent = menu->parent; 2606 char_u *accel_key; 2607 char_u mnemonic_str[MB_LEN_MAX]; 2608 int n; 2609 PtArg_t args[5]; 2610 2611 menu->submenu_id = menu->id = NULL; 2612 2613 if( menu_is_menubar( menu->name ) ) 2614 { 2615 2616 accel_key = vim_strchr( menu->name, '&' ); 2617 if( accel_key != NULL ) 2618 { 2619 mnemonic_str[0] = accel_key[1]; 2620 mnemonic_str[1] = NUL; 2621 } 2622 2623 /* Create the menu button */ 2624 n = 0; 2625 PtSetArg( &args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0 ); 2626 PtSetArg( &args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0 ); 2627 if( accel_key != NULL ) 2628 PtSetArg( &args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 0 ); 2629 PtSetArg( &args[ n++ ], Pt_ARG_POINTER, menu, 0 ); 2630 2631 if( parent != NULL ) 2632 PtSetArg( &args[ n++ ], Pt_ARG_BUTTON_TYPE, Pt_MENU_RIGHT, 0 ); 2633 2634 menu->id = PtCreateWidget( PtMenuButton, 2635 (parent == NULL) ? gui.vimMenuBar : parent->submenu_id, 2636 n, args ); 2637 2638 PtAddCallback( menu->id, Pt_CB_ARM, gui_ph_handle_pulldown_menu, menu ); 2639 2640 /* Create the actual menu */ 2641 n = 0; 2642 if( parent != NULL ) 2643 PtSetArg( &args[ n++ ], Pt_ARG_MENU_FLAGS, Pt_TRUE, Pt_MENU_CHILD ); 2644 2645 menu->submenu_id = PtCreateWidget( PtMenu, menu->id, n, args ); 2646 2647 if( parent == NULL ) 2648 { 2649 PtAddCallback( menu->submenu_id, Pt_CB_UNREALIZED, 2650 gui_ph_handle_menu_unrealized, menu ); 2651 2652 if( menu->mnemonic != 0 ) 2653 { 2654 PtAddHotkeyHandler( gui.vimWindow, tolower( menu->mnemonic ), 2655 Pk_KM_Alt, 0, menu, gui_ph_handle_pulldown_menu ); 2656 } 2657 } 2658 2659 gui_ph_position_menu( menu->id, menu->priority ); 2660 2661 /* Redraw menubar here instead of gui_mch_draw_menubar */ 2662 if( gui.menu_is_active ) 2663 PtRealizeWidget( menu->id ); 2664 } 2665 else if( menu_is_popup( menu->name ) ) 2666 { 2667 menu->submenu_id = PtCreateWidget( PtMenu, gui.vimWindow, 0, NULL ); 2668 PtAddCallback( menu->submenu_id, Pt_CB_UNREALIZED, 2669 gui_ph_handle_menu_unrealized, menu ); 2670 } 2671} 2672 2673 void 2674gui_mch_add_menu_item(vimmenu_T *menu, int index) 2675{ 2676 vimmenu_T *parent = menu->parent; 2677 char_u *accel_key; 2678 char_u mnemonic_str[MB_LEN_MAX]; 2679 int n; 2680 PtArg_t args[13]; 2681 2682 n = 0; 2683 PtSetArg( &args[ n++ ], Pt_ARG_POINTER, menu, 0 ); 2684 2685#ifdef FEAT_TOOLBAR 2686 if( menu_is_toolbar( parent->name ) ) 2687 { 2688 if( menu_is_separator( menu->name ) ) 2689 { 2690 PtSetArg( &args[ n++ ], Pt_ARG_SEP_FLAGS, 2691 Pt_SEP_VERTICAL, Pt_SEP_ORIENTATION ); 2692 PtSetArg( &args[ n++ ], Pt_ARG_SEP_TYPE, Pt_ETCHED_IN, 0 ); 2693 PtSetArg( &args[ n++ ], Pt_ARG_ANCHOR_FLAGS, 2694 Pt_TRUE, Pt_ANCHOR_TOP_BOTTOM ); 2695 PtSetArg( &args[ n++ ], Pt_ARG_WIDTH, 2, 0 ); 2696 menu->id = PtCreateWidget( PtSeparator, gui.vimToolBar, n, args ); 2697 } 2698 else 2699 { 2700 if( strstr( (const char *) p_toolbar, "text" ) != NULL ) 2701 { 2702 PtSetArg( &args[ n++ ], Pt_ARG_BALLOON_POSITION, 2703 Pt_BALLOON_BOTTOM, 0 ); 2704 PtSetArg( &args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0 ); 2705 PtSetArg( &args[ n++ ], Pt_ARG_TEXT_FONT, "TextFont08", 0 ); 2706 } 2707 if( ( strstr( (const char *) p_toolbar, "icons" ) != NULL ) && 2708 ( gui_ph_toolbar_images != NULL ) ) 2709 { 2710 PtSetArg( &args[ n++ ], Pt_ARG_LABEL_IMAGE, 2711 gui_ph_toolbar_find_icon( menu ), 0 ); 2712 PtSetArg( &args[ n++ ], Pt_ARG_LABEL_TYPE, Pt_TEXT_IMAGE, 0 ); 2713 PtSetArg( &args[ n++ ], Pt_ARG_TEXT_IMAGE_SPACING, 0, 0 ); 2714 } 2715 if( strstr( (const char *) p_toolbar, "tooltips" ) != NULL ) 2716 { 2717 PtSetArg( &args[ n++ ], Pt_ARG_LABEL_BALLOON, 2718 gui_ph_show_tooltip, 0 ); 2719 PtSetArg( &args[ n++ ], Pt_ARG_LABEL_FLAGS, 2720 Pt_TRUE, Pt_SHOW_BALLOON ); 2721 } 2722 PtSetArg( &args[ n++ ], Pt_ARG_MARGIN_HEIGHT, 1, 0 ); 2723 PtSetArg( &args[ n++ ], Pt_ARG_MARGIN_WIDTH, 1, 0 ); 2724 PtSetArg( &args[ n++ ], Pt_ARG_FLAGS, Pt_FALSE, 2725 Pt_HIGHLIGHTED | Pt_GETS_FOCUS ); 2726 PtSetArg( &args[ n++ ], Pt_ARG_FILL_COLOR, Pg_TRANSPARENT, 0 ); 2727 menu->id = PtCreateWidget( PtButton, gui.vimToolBar, n, args ); 2728 2729 PtAddCallback( menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu ); 2730 } 2731 /* Update toolbar if it's open */ 2732 if( PtWidgetIsRealized( gui.vimToolBar ) ) 2733 PtRealizeWidget( menu->id ); 2734 } 2735 else 2736#endif 2737 if( menu_is_separator( menu->name ) ) 2738 { 2739 menu->id = PtCreateWidget( PtSeparator, parent->submenu_id, n, args ); 2740 } 2741 else 2742 { 2743 accel_key = vim_strchr( menu->name, '&' ); 2744 if( accel_key != NULL ) 2745 { 2746 mnemonic_str[0] = accel_key[1]; 2747 mnemonic_str[1] = NUL; 2748 } 2749 2750 PtSetArg( &args[ n++ ], Pt_ARG_TEXT_STRING, menu->dname, 0 ); 2751 if( accel_key != NULL ) 2752 PtSetArg( &args[ n++ ], Pt_ARG_ACCEL_KEY, mnemonic_str, 2753 0 ); 2754 2755 PtSetArg( &args[ n++ ], Pt_ARG_ACCEL_TEXT, menu->actext, 0 ); 2756 2757 menu->id = PtCreateWidget( PtMenuButton, parent->submenu_id, n, args ); 2758 2759 PtAddCallback( menu->id, Pt_CB_ACTIVATE, gui_ph_handle_menu, menu ); 2760 2761#ifdef USE_PANEL_GROUP 2762 if( gui_ph_is_buffer_item( menu, parent ) == TRUE ) 2763 { 2764 PtAddCallback( menu->id, Pt_CB_DESTROYED, 2765 gui_ph_handle_buffer_remove, menu ); 2766 gui_ph_pg_add_buffer( menu->dname ); 2767 } 2768#endif 2769 } 2770 2771 gui_ph_position_menu( menu->id, menu->priority ); 2772} 2773 2774 void 2775gui_mch_destroy_menu(vimmenu_T *menu) 2776{ 2777 if( menu->submenu_id != NULL ) 2778 PtDestroyWidget( menu->submenu_id ); 2779 if( menu->id != NULL ) 2780 PtDestroyWidget( menu->id ); 2781 2782 menu->submenu_id = NULL; 2783 menu->id = NULL; 2784} 2785 2786 void 2787gui_mch_menu_grey(vimmenu_T *menu, int grey) 2788{ 2789 long flags, mask, fields; 2790 2791 if( menu->id == NULL ) 2792 return; 2793 2794 flags = PtWidgetFlags( menu->id ); 2795 if( PtWidgetIsClass( menu->id, PtMenuButton ) && 2796 PtWidgetIsClass( PtWidgetParent( menu->id ), PtMenu ) ) 2797 { 2798 fields = Pt_FALSE; 2799 mask = Pt_SELECTABLE | Pt_HIGHLIGHTED; 2800 } 2801 else 2802 { 2803 fields = Pt_TRUE; 2804 mask = Pt_BLOCKED | Pt_GHOST; 2805 } 2806 2807 if( ! grey ) 2808 fields = ~fields; 2809 2810 PtSetResource( menu->id, Pt_ARG_FLAGS, fields, 2811 mask ); 2812} 2813 2814 void 2815gui_mch_menu_hidden(vimmenu_T *menu, int hidden) 2816{ 2817 /* TODO: [un]realize the widget? */ 2818} 2819 2820 void 2821gui_mch_draw_menubar(void) 2822{ 2823 /* The only time a redraw is needed is when a menu button 2824 * is added to the menubar, and that is detected and the bar 2825 * redrawn in gui_mch_add_menu_item 2826 */ 2827} 2828 2829 void 2830gui_mch_show_popupmenu(vimmenu_T *menu) 2831{ 2832 PtSetResource( menu->submenu_id, Pt_ARG_POS, &abs_mouse, 0 ); 2833 PtRealizeWidget( menu->submenu_id ); 2834} 2835 2836 void 2837gui_mch_toggle_tearoffs(int enable) 2838{ 2839 /* No tearoffs yet */ 2840} 2841 2842#endif 2843 2844#if defined( FEAT_TOOLBAR ) || defined( PROTO ) 2845 void 2846gui_mch_show_toolbar(int showit) 2847{ 2848 if( showit ) 2849 PtRealizeWidget( gui.vimToolBar ); 2850 else 2851 PtUnrealizeWidget( gui.vimToolBar ); 2852} 2853#endif 2854 2855/****************************************************************************/ 2856/* Fonts */ 2857 2858 static GuiFont 2859gui_ph_get_font( 2860 char_u *font_name, 2861 int_u font_flags, 2862 int_u font_size, 2863 /* Check whether the resulting font has the font flags and size that 2864 * was asked for */ 2865 int_u enforce 2866 ) 2867{ 2868 char_u *font_tag; 2869 FontQueryInfo info; 2870 int_u style; 2871 2872 font_tag = alloc( MAX_FONT_TAG ); 2873 if( font_tag != NULL ) 2874 { 2875 if( PfGenerateFontName( font_name, font_flags, font_size, 2876 font_tag ) != NULL ) 2877 { 2878 /* Enforce some limits on the font used */ 2879 style = PHFONT_INFO_FIXED; 2880 2881 if( enforce & PF_STYLE_BOLD ) 2882 style |= PHFONT_INFO_BOLD; 2883 if( enforce & PF_STYLE_ANTIALIAS ) 2884 style |= PHFONT_INFO_ALIAS; 2885 if( enforce & PF_STYLE_ITALIC ) 2886 style |= PHFONT_INFO_ITALIC; 2887 2888 PfQueryFontInfo( font_tag, &info ); 2889 2890 if( info.size == 0 ) 2891 font_size = 0; 2892 2893 /* Make sure font size matches, and that the font style 2894 * at least has the bits we're checking for */ 2895 if( font_size == info.size && 2896 style == (info.style & style) ) 2897 return( (GuiFont) font_tag ); 2898 } 2899 vim_free( font_tag ); 2900 } 2901 return( NULL ); 2902} 2903 2904/* 2905 * Split up the vim font name 2906 * 2907 * vim_font is in the form of 2908 * <name>:s<height>:a:b:i 2909 * 2910 * a = antialias 2911 * b = bold 2912 * i = italic 2913 * 2914 */ 2915 2916 static int 2917gui_ph_parse_font_name( 2918 char_u *vim_font, 2919 char_u **font_name, 2920 int_u *font_flags, 2921 int_u *font_size ) 2922{ 2923 char_u *mark; 2924 int_u name_len, size; 2925 2926 mark = vim_strchr( vim_font, ':' ); 2927 if( mark == NULL ) 2928 name_len = STRLEN( vim_font ); 2929 else 2930 name_len = (int_u) ( mark - vim_font ); 2931 2932 *font_name = vim_strnsave( vim_font, name_len ); 2933 if( *font_name != NULL ) 2934 { 2935 if( mark != NULL ) 2936 { 2937 while( *mark != NUL && *mark++ == ':') 2938 { 2939 switch( tolower( *mark++ ) ) 2940 { 2941 case 'a': *font_flags |= PF_STYLE_ANTIALIAS; break; 2942 case 'b': *font_flags |= PF_STYLE_BOLD; break; 2943 case 'i': *font_flags |= PF_STYLE_ITALIC; break; 2944 2945 case 's': 2946 size = getdigits( &mark ); 2947 /* Restrict the size to some vague limits */ 2948 if( size < 1 || size > 100 ) 2949 size = 8; 2950 2951 *font_size = size; 2952 break; 2953 2954 default: 2955 break; 2956 } 2957 } 2958 } 2959 return( TRUE ); 2960 } 2961 return( FALSE ); 2962} 2963 2964 int 2965gui_mch_init_font(char_u *vim_font_name, int fontset) 2966{ 2967 char_u *font_tag; 2968 char_u *font_name = NULL; 2969 int_u font_flags = 0; 2970 int_u font_size = 12; 2971 2972 FontQueryInfo info; 2973 PhRect_t extent; 2974 2975 if( vim_font_name == NULL ) 2976 { 2977 /* Default font */ 2978 vim_font_name = "PC Terminal"; 2979 } 2980 2981 if( STRCMP( vim_font_name, "*" ) == 0 ) 2982 { 2983 font_tag = PtFontSelection( gui.vimWindow, NULL, NULL, 2984 "pcterm12", -1, PHFONT_FIXED, NULL ); 2985 2986 if( font_tag == NULL ) 2987 return( FAIL ); 2988 2989 gui_mch_free_font( gui.norm_font ); 2990 gui.norm_font = font_tag; 2991 2992 PfQueryFontInfo( font_tag, &info ); 2993 font_name = vim_strsave( info.font ); 2994 } 2995 else 2996 { 2997 if( gui_ph_parse_font_name( vim_font_name, &font_name, &font_flags, 2998 &font_size ) == FALSE ) 2999 return( FAIL ); 3000 3001 font_tag = gui_ph_get_font( font_name, font_flags, font_size, 0 ); 3002 if( font_tag == NULL ) 3003 { 3004 vim_free( font_name ); 3005 return( FAIL ); 3006 } 3007 3008 gui_mch_free_font( gui.norm_font ); 3009 gui.norm_font = font_tag; 3010 } 3011 3012 gui_mch_free_font( gui.bold_font ); 3013 gui.bold_font = gui_ph_get_font( font_name, font_flags | PF_STYLE_BOLD, 3014 font_size, PF_STYLE_BOLD ); 3015 3016 gui_mch_free_font( gui.ital_font ); 3017 gui.ital_font = gui_ph_get_font( font_name, font_flags | PF_STYLE_ITALIC, 3018 font_size, PF_STYLE_ITALIC ); 3019 3020 /* This extent was brought to you by the letter 'g' */ 3021 PfExtentText( &extent, NULL, font_tag, "g", 1 ); 3022 3023 gui.char_width = extent.lr.x - extent.ul.x + 1; 3024 gui.char_height = (- extent.ul.y) + extent.lr.y + 1; 3025 gui.char_ascent = - extent.ul.y; 3026 3027 vim_free( font_name ); 3028 return( OK ); 3029} 3030 3031/* 3032 * Adjust gui.char_height (after 'linespace' was changed). 3033 */ 3034 int 3035gui_mch_adjust_charheight(void) 3036{ 3037 FontQueryInfo info; 3038 3039 PfQueryFontInfo( gui.norm_font, &info ); 3040 3041 gui.char_height = - info.ascender + info.descender + p_linespace; 3042 gui.char_ascent = - info.ascender + p_linespace / 2; 3043 3044 return( OK ); 3045} 3046 3047 GuiFont 3048gui_mch_get_font(char_u *vim_font_name, int report_error) 3049{ 3050 char_u *font_name; 3051 char_u *font_tag; 3052 int_u font_size = 12; 3053 int_u font_flags = 0; 3054 3055 if( gui_ph_parse_font_name( vim_font_name, &font_name, &font_flags, 3056 &font_size ) != FALSE ) 3057 { 3058 font_tag = gui_ph_get_font( font_name, font_flags, font_size, -1 ); 3059 vim_free( font_name ); 3060 3061 if( font_tag != NULL ) 3062 return( (GuiFont) font_tag ); 3063 } 3064 3065 if( report_error ) 3066 EMSG2(e_font, vim_font_name ); 3067 3068 return( FAIL ); 3069} 3070 3071#if defined(FEAT_EVAL) || defined(PROTO) 3072/* 3073 * Return the name of font "font" in allocated memory. 3074 * Don't know how to get the actual name, thus use the provided name. 3075 */ 3076 char_u * 3077gui_mch_get_fontname(font, name) 3078 GuiFont font; 3079 char_u *name; 3080{ 3081 if (name == NULL) 3082 return NULL; 3083 return vim_strsave(name); 3084} 3085#endif 3086 3087 void 3088gui_mch_set_font(GuiFont font) 3089{ 3090 PgSetFont( font ); 3091} 3092 3093 void 3094gui_mch_free_font(GuiFont font) 3095{ 3096 vim_free( font ); 3097} 3098 3099