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