Mercurial > vim
annotate src/gui_haiku.cc @ 20151:39cb08f7f6b0
Added tag v8.2.0630 for changeset 1e76da634877cf30a1c7cd1374e1ed6703b9413c
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 24 Apr 2020 21:30:03 +0200 |
parents | 352701a626ed |
children | bac01efdf059 |
rev | line source |
---|---|
19526 | 1 /* vi:set ts=8 sts=4 sw=4: |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * BeBox GUI support Copyright 1998 by Olaf Seibert. | |
5 * All Rights Reserved. | |
6 * | |
7 * Do ":help uganda" in Vim to read copying and usage conditions. | |
8 * Do ":help credits" in Vim to see a list of people who contributed. | |
9 * | |
10 * Based on "GUI support for the Buzzword Enhanced Operating System." | |
11 * | |
12 * Ported to R4 by Richard Offer <richard@whitequeen.com> Jul 99 | |
13 * | |
14 * Haiku support by Siarzhuk Zharski <imker@gmx.li> Apr-Mai 2009 | |
15 * | |
16 */ | |
17 | |
18 /* | |
19 * Structure of the Haiku GUI code: | |
20 * | |
21 * There are 3 threads. | |
22 * 1. The initial thread. In gui_mch_prepare() this gets to run the | |
23 * BApplication message loop. But before it starts doing that, | |
24 * it creates thread 2 | |
25 * 2. The main() thread. This thread is created in gui_mch_prepare() | |
26 * and its purpose in life is to call main(argc, argv) again. | |
27 * This thread is doing the bulk of the work. | |
28 * 3. Sooner or later, a window is opened by the main() thread. This | |
29 * causes a second message loop to be created: the window thread. | |
30 * | |
31 * == alternatively === | |
32 * | |
33 * #if RUN_BAPPLICATION_IN_NEW_THREAD... | |
34 * | |
35 * 1. The initial thread. In gui_mch_prepare() this gets to spawn | |
36 * thread 2. After doing that, it returns to main() to do the | |
37 * bulk of the work, being the main() thread. | |
38 * 2. Runs the BApplication. | |
39 * 3. The window thread, just like in the first case. | |
40 * | |
41 * This second alternative is cleaner from Vim's viewpoint. However, | |
42 * the BeBook seems to assume everywhere that the BApplication *must* | |
43 * run in the initial thread. So perhaps doing otherwise is very wrong. | |
44 * | |
45 * However, from a B_SINGLE_LAUNCH viewpoint, the first is better. | |
46 * If Vim is marked "Single Launch" in its application resources, | |
47 * and a file is dropped on the Vim icon, and another Vim is already | |
48 * running, the file is passed on to the earlier Vim. This happens | |
49 * in BApplication::Run(). So we want Vim to terminate if | |
50 * BApplication::Run() terminates. (See the BeBook, on BApplication. | |
51 * However, it seems that the second copy of Vim isn't even started | |
52 * in this case... which is for the better since I wouldn't know how | |
53 * to detect this case.) | |
54 * | |
55 * Communication between these threads occurs mostly by translating | |
56 * BMessages that come in and posting an appropriate translation on | |
57 * the VDCMP (Vim Direct Communication Message Port). Therefore the | |
58 * actions required for keypresses and window resizes, etc, are mostly | |
59 * performed in the main() thread. | |
60 * | |
61 * A notable exception to this is the Draw() event. The redrawing of | |
62 * the window contents is performed asynchronously from the window | |
63 * thread. To make this work correctly, a locking protocol is used when | |
64 * any thread is accessing the essential variables that are used by | |
65 * the window thread. | |
66 * | |
67 * This locking protocol consists of locking Vim's window. This is both | |
68 * convenient and necessary. | |
69 */ | |
70 | |
71 extern "C" { | |
72 | |
73 #include <assert.h> | |
74 #include <float.h> | |
75 #include <syslog.h> | |
76 | |
77 #include "vim.h" | |
78 #include "globals.h" | |
79 #include "proto.h" | |
80 #include "version.h" | |
81 | |
82 } // extern "C" | |
83 | |
84 // ---------------- start of header part ---------------- | |
85 | |
86 //#include <Alert.h> | |
87 #include <Application.h> | |
88 #include <Beep.h> | |
89 #include <Bitmap.h> | |
90 #include <Box.h> | |
91 #include <Button.h> | |
92 #include <Clipboard.h> | |
93 #include <Debug.h> | |
94 //#include <Directory.h> | |
95 //#include <Entry.h> | |
96 #include <File.h> | |
97 #include <FilePanel.h> | |
98 #include <FindDirectory.h> | |
99 //#include <Font.h> | |
100 #include <IconUtils.h> | |
101 #include <Input.h> | |
102 #include <ListView.h> | |
103 #include <MenuBar.h> | |
104 #include <MenuItem.h> | |
105 //#include <MessageQueue.h> | |
106 //#include <OS.h> | |
107 #include <Path.h> | |
108 #include <PictureButton.h> | |
109 #include <PopUpMenu.h> | |
110 //#include <Region.h> | |
111 #include <Resources.h> | |
112 //#include <Roster.h> | |
113 #include <Screen.h> | |
114 #include <ScrollBar.h> | |
115 #include <ScrollView.h> | |
116 #include <String.h> | |
117 #include <StringView.h> | |
118 //#include <SupportDefs.h> | |
119 #include <TabView.h> | |
120 #include <TextControl.h> | |
121 #include <TextView.h> | |
122 #include <TranslationUtils.h> | |
123 #include <TranslatorFormats.h> | |
124 #include <View.h> | |
125 #include <Window.h> | |
126 | |
127 class VimApp; | |
128 class VimFormView; | |
129 class VimTextAreaView; | |
130 class VimWindow; | |
131 class VimToolbar; | |
132 class VimTabLine; | |
133 | |
134 extern key_map *keyMap; | |
135 extern char *keyMapChars; | |
136 | |
137 extern int main(int argc, char **argv); | |
138 | |
139 #ifndef B_MAX_PORT_COUNT | |
140 #define B_MAX_PORT_COUNT 255 | |
141 #endif | |
142 | |
143 // VimApp seems comparable to the X "vimShell" | |
144 class VimApp: public BApplication | |
145 { | |
146 typedef BApplication Inherited; | |
147 public: | |
148 VimApp(const char *appsig); | |
149 ~VimApp(); | |
150 | |
151 // callbacks: | |
152 #if 0 | |
153 virtual void DispatchMessage(BMessage *m, BHandler *h) | |
154 { | |
155 m->PrintToStream(); | |
156 Inherited::DispatchMessage(m, h); | |
157 } | |
158 #endif | |
159 virtual void ReadyToRun(); | |
160 virtual void ArgvReceived(int32 argc, char **argv); | |
161 virtual void RefsReceived(BMessage *m); | |
162 virtual bool QuitRequested(); | |
163 virtual void MessageReceived(BMessage *m); | |
164 | |
165 static void SendRefs(BMessage *m, bool changedir); | |
166 | |
167 sem_id fFilePanelSem; | |
168 BFilePanel* fFilePanel; | |
169 BPath fBrowsedPath; | |
170 private: | |
171 }; | |
172 | |
173 class VimWindow: public BWindow | |
174 { | |
175 typedef BWindow Inherited; | |
176 public: | |
177 VimWindow(); | |
178 ~VimWindow(); | |
179 | |
180 // virtual void DispatchMessage(BMessage *m, BHandler *h); | |
181 virtual void WindowActivated(bool active); | |
182 virtual bool QuitRequested(); | |
183 | |
184 VimFormView *formView; | |
185 | |
186 private: | |
187 void init(); | |
188 | |
189 }; | |
190 | |
191 class VimFormView: public BView | |
192 { | |
193 typedef BView Inherited; | |
194 public: | |
195 VimFormView(BRect frame); | |
196 ~VimFormView(); | |
197 | |
198 // callbacks: | |
199 virtual void AllAttached(); | |
200 virtual void FrameResized(float new_width, float new_height); | |
201 | |
202 #define MENUBAR_MARGIN 1 | |
203 float MenuHeight() const | |
204 { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; } | |
205 BMenuBar *MenuBar() const | |
206 { return menuBar; } | |
207 | |
208 private: | |
209 void init(BRect); | |
210 | |
211 BMenuBar *menuBar; | |
212 VimTextAreaView *textArea; | |
213 | |
214 #ifdef FEAT_TOOLBAR | |
215 public: | |
216 float ToolbarHeight() const; | |
217 VimToolbar *ToolBar() const | |
218 { return toolBar; } | |
219 private: | |
220 VimToolbar *toolBar; | |
221 #endif | |
222 | |
223 #ifdef FEAT_GUI_TABLINE | |
224 public: | |
225 VimTabLine *TabLine() const { return tabLine; } | |
226 bool IsShowingTabLine() const { return showingTabLine; } | |
227 void SetShowingTabLine(bool showing) { showingTabLine = showing; } | |
228 float TablineHeight() const; | |
229 private: | |
230 VimTabLine *tabLine; | |
231 int showingTabLine; | |
232 #endif | |
233 }; | |
234 | |
235 class VimTextAreaView: public BView | |
236 { | |
237 typedef BView Inherited; | |
238 public: | |
239 VimTextAreaView(BRect frame); | |
240 ~VimTextAreaView(); | |
241 | |
242 // callbacks: | |
243 virtual void Draw(BRect updateRect); | |
244 virtual void KeyDown(const char *bytes, int32 numBytes); | |
245 virtual void MouseDown(BPoint point); | |
246 virtual void MouseUp(BPoint point); | |
247 virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); | |
248 virtual void MessageReceived(BMessage *m); | |
249 | |
250 // own functions: | |
251 int mchInitFont(char_u *name); | |
252 void mchDrawString(int row, int col, char_u *s, int len, int flags); | |
253 void mchClearBlock(int row1, int col1, int row2, int col2); | |
254 void mchClearAll(); | |
255 void mchDeleteLines(int row, int num_lines); | |
256 void mchInsertLines(int row, int num_lines); | |
257 | |
258 static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers); | |
259 static void guiMouseMoved(int x, int y); | |
260 static void guiBlankMouse(bool should_hide); | |
261 static int_u mouseModifiersToVim(int32 beModifiers); | |
262 | |
263 int32 mouseDragEventCount; | |
264 | |
265 #ifdef FEAT_MBYTE_IME | |
266 void DrawIMString(void); | |
267 #endif | |
268 | |
269 private: | |
270 void init(BRect); | |
271 | |
272 int_u vimMouseButton; | |
273 int_u vimMouseModifiers; | |
274 | |
275 #ifdef FEAT_MBYTE_IME | |
276 struct { | |
277 BMessenger* messenger; | |
278 BMessage* message; | |
279 BPoint location; | |
280 int row; | |
281 int col; | |
282 int count; | |
283 } IMData; | |
284 #endif | |
285 }; | |
286 | |
287 class VimScrollBar: public BScrollBar | |
288 { | |
289 typedef BScrollBar Inherited; | |
290 public: | |
291 VimScrollBar(scrollbar_T *gsb, orientation posture); | |
292 ~VimScrollBar(); | |
293 | |
294 virtual void ValueChanged(float newValue); | |
295 virtual void MouseUp(BPoint where); | |
296 void SetValue(float newval); | |
297 scrollbar_T *getGsb() | |
298 { return gsb; } | |
299 | |
300 int32 scrollEventCount; | |
301 | |
302 private: | |
303 scrollbar_T *gsb; | |
304 float ignoreValue; | |
305 }; | |
306 | |
307 | |
308 #ifdef FEAT_TOOLBAR | |
309 | |
310 class VimToolbar : public BBox | |
311 { | |
312 static BBitmap *normalButtonsBitmap; | |
313 static BBitmap *grayedButtonsBitmap; | |
314 | |
315 BBitmap *LoadVimBitmap(const char* fileName); | |
316 bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed); | |
317 bool ModifyBitmapToGrayed(BBitmap *bitmap); | |
318 | |
319 BList fButtonsList; | |
320 void InvalidateLayout(); | |
321 | |
322 public: | |
323 VimToolbar(BRect frame, const char * name); | |
324 ~VimToolbar(); | |
325 | |
326 bool PrepareButtonBitmaps(); | |
327 | |
328 bool AddButton(int32 index, vimmenu_T *menu); | |
329 bool RemoveButton(vimmenu_T *menu); | |
330 bool GrayButton(vimmenu_T *menu, int grey); | |
331 | |
332 float ToolbarHeight() const; | |
333 virtual void AttachedToWindow(); | |
334 }; | |
335 | |
336 BBitmap *VimToolbar::normalButtonsBitmap = NULL; | |
337 BBitmap *VimToolbar::grayedButtonsBitmap = NULL; | |
338 | |
339 const float ToolbarMargin = 3.; | |
340 const float ButtonMargin = 3.; | |
341 | |
342 #endif //FEAT_TOOLBAR | |
343 | |
344 #ifdef FEAT_GUI_TABLINE | |
345 | |
346 class VimTabLine : public BTabView | |
347 { | |
348 public: | |
349 class VimTab : public BTab { | |
350 public: | |
351 VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {} | |
352 | |
353 virtual void Select(BView* owner); | |
354 }; | |
355 | |
356 VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL, | |
357 B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {} | |
358 | |
359 float TablineHeight() const; | |
360 virtual void MouseDown(BPoint point); | |
361 }; | |
362 | |
363 #endif //FEAT_GUI_TABLINE | |
364 | |
365 | |
366 // For caching the fonts that are used; | |
367 // Vim seems rather sloppy in this regard. | |
368 class VimFont: public BFont | |
369 { | |
370 typedef BFont Inherited; | |
371 public: | |
372 VimFont(); | |
373 VimFont(const VimFont *rhs); | |
374 VimFont(const BFont *rhs); | |
375 VimFont(const VimFont &rhs); | |
376 ~VimFont(); | |
377 | |
378 VimFont *next; | |
379 int refcount; | |
380 char_u *name; | |
381 | |
382 private: | |
383 void init(); | |
384 }; | |
385 | |
386 #if defined(FEAT_GUI_DIALOG) | |
387 | |
388 class VimDialog : public BWindow | |
389 { | |
390 typedef BWindow Inherited; | |
391 | |
392 BButton* _CreateButton(int32 which, const char* label); | |
393 | |
394 public: | |
395 | |
396 class View : public BView { | |
397 typedef BView Inherited; | |
398 | |
399 public: | |
400 View(BRect frame); | |
401 ~View(); | |
402 | |
403 virtual void Draw(BRect updateRect); | |
404 void InitIcon(int32 type); | |
405 | |
406 private: | |
407 BBitmap* fIconBitmap; | |
408 }; | |
409 | |
410 VimDialog(int type, const char *title, const char *message, | |
411 const char *buttons, int dfltbutton, const char *textfield, | |
412 int ex_cmd); | |
413 ~VimDialog(); | |
414 | |
415 int Go(); | |
416 | |
417 virtual void MessageReceived(BMessage *msg); | |
418 | |
419 private: | |
420 sem_id fDialogSem; | |
421 int fDialogValue; | |
422 BList fButtonsList; | |
423 BTextView* fMessageView; | |
424 BTextControl* fInputControl; | |
425 const char* fInputValue; | |
426 }; | |
427 | |
428 class VimSelectFontDialog : public BWindow | |
429 { | |
430 typedef BWindow Inherited; | |
431 | |
432 void _CleanList(BListView* list); | |
433 void _UpdateFontStyles(); | |
434 void _UpdateSizeInputPreview(); | |
435 void _UpdateFontPreview(); | |
436 bool _UpdateFromListItem(BListView* list, char* text, int textSize); | |
437 public: | |
438 | |
439 VimSelectFontDialog(font_family* family, font_style* style, float* size); | |
440 ~VimSelectFontDialog(); | |
441 | |
442 bool Go(); | |
443 | |
444 virtual void MessageReceived(BMessage *msg); | |
445 | |
446 private: | |
447 status_t fStatus; | |
448 sem_id fDialogSem; | |
449 bool fDialogValue; | |
450 font_family* fFamily; | |
451 font_style* fStyle; | |
452 float* fSize; | |
453 font_family fFontFamily; | |
454 font_style fFontStyle; | |
455 float fFontSize; | |
456 BStringView* fPreview; | |
457 BListView* fFamiliesList; | |
458 BListView* fStylesList; | |
459 BListView* fSizesList; | |
460 BTextControl* fSizesInput; | |
461 }; | |
462 | |
463 #endif // FEAT_GUI_DIALOG | |
464 | |
465 // ---------------- end of GUI classes ---------------- | |
466 | |
467 struct MainArgs { | |
468 int argc; | |
469 char **argv; | |
470 }; | |
471 | |
472 // These messages are copied through the VDCMP. | |
473 // Therefore they ought not to have anything fancy. | |
474 // They must be of POD type (Plain Old Data) | |
475 // as the C++ standard calls them. | |
476 | |
477 #define KEY_MSG_BUFSIZ 7 | |
478 #if KEY_MSG_BUFSIZ < MAX_KEY_CODE_LEN | |
479 #error Increase KEY_MSG_BUFSIZ! | |
480 #endif | |
481 | |
482 struct VimKeyMsg { | |
483 char_u length; | |
484 char_u chars[KEY_MSG_BUFSIZ]; // contains Vim encoding | |
485 bool csi_escape; | |
486 }; | |
487 | |
488 struct VimResizeMsg { | |
489 int width; | |
490 int height; | |
491 }; | |
492 | |
493 struct VimScrollBarMsg { | |
494 VimScrollBar *sb; | |
495 long value; | |
496 int stillDragging; | |
497 }; | |
498 | |
499 struct VimMenuMsg { | |
500 vimmenu_T *guiMenu; | |
501 }; | |
502 | |
503 struct VimMouseMsg { | |
504 int button; | |
505 int x; | |
506 int y; | |
507 int repeated_click; | |
508 int_u modifiers; | |
509 }; | |
510 | |
511 struct VimMouseMovedMsg { | |
512 int x; | |
513 int y; | |
514 }; | |
515 | |
516 struct VimFocusMsg { | |
517 bool active; | |
518 }; | |
519 | |
520 struct VimRefsMsg { | |
521 BMessage *message; | |
522 bool changedir; | |
523 }; | |
524 | |
525 struct VimTablineMsg { | |
526 int index; | |
527 }; | |
528 | |
529 struct VimTablineMenuMsg { | |
530 int index; | |
531 int event; | |
532 }; | |
533 | |
534 struct VimMsg { | |
535 enum VimMsgType { | |
536 Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu | |
537 }; | |
538 | |
539 union { | |
540 struct VimKeyMsg Key; | |
541 struct VimResizeMsg NewSize; | |
542 struct VimScrollBarMsg Scroll; | |
543 struct VimMenuMsg Menu; | |
544 struct VimMouseMsg Mouse; | |
545 struct VimMouseMovedMsg MouseMoved; | |
546 struct VimFocusMsg Focus; | |
547 struct VimRefsMsg Refs; | |
548 struct VimTablineMsg Tabline; | |
549 struct VimTablineMenuMsg TablineMenu; | |
550 } u; | |
551 }; | |
552 | |
553 #define RGB(r, g, b) ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0) | |
554 #define GUI_TO_RGB(g) { (g) >> 16, (g) >> 8, (g) >> 0, 255 } | |
555 | |
556 // ---------------- end of header part ---------------- | |
557 | |
558 static struct specialkey | |
559 { | |
560 uint16 BeKeys; | |
561 #define KEY(a,b) ((a)<<8|(b)) | |
562 #define K(a) KEY(0,a) // for ASCII codes | |
563 #define F(b) KEY(1,b) // for scancodes | |
564 char_u vim_code0; | |
565 char_u vim_code1; | |
566 } special_keys[] = | |
567 { | |
568 {K(B_UP_ARROW), 'k', 'u'}, | |
569 {K(B_DOWN_ARROW), 'k', 'd'}, | |
570 {K(B_LEFT_ARROW), 'k', 'l'}, | |
571 {K(B_RIGHT_ARROW), 'k', 'r'}, | |
572 {K(B_BACKSPACE), 'k', 'b'}, | |
573 {K(B_INSERT), 'k', 'I'}, | |
574 {K(B_DELETE), 'k', 'D'}, | |
575 {K(B_HOME), 'k', 'h'}, | |
576 {K(B_END), '@', '7'}, | |
577 {K(B_PAGE_UP), 'k', 'P'}, // XK_Prior | |
578 {K(B_PAGE_DOWN), 'k', 'N'}, // XK_Next, | |
579 | |
580 #define FIRST_FUNCTION_KEY 11 | |
581 {F(B_F1_KEY), 'k', '1'}, | |
582 {F(B_F2_KEY), 'k', '2'}, | |
583 {F(B_F3_KEY), 'k', '3'}, | |
584 {F(B_F4_KEY), 'k', '4'}, | |
585 {F(B_F5_KEY), 'k', '5'}, | |
586 {F(B_F6_KEY), 'k', '6'}, | |
587 {F(B_F7_KEY), 'k', '7'}, | |
588 {F(B_F8_KEY), 'k', '8'}, | |
589 {F(B_F9_KEY), 'k', '9'}, | |
590 {F(B_F10_KEY), 'k', ';'}, | |
591 | |
592 {F(B_F11_KEY), 'F', '1'}, | |
593 {F(B_F12_KEY), 'F', '2'}, | |
594 // {XK_F13, 'F', '3'}, // would be print screen | |
595 // sysreq | |
596 {F(0x0F), 'F', '4'}, // scroll lock | |
597 {F(0x10), 'F', '5'}, // pause/break | |
598 // {XK_F16, 'F', '6'}, | |
599 // {XK_F17, 'F', '7'}, | |
600 // {XK_F18, 'F', '8'}, | |
601 // {XK_F19, 'F', '9'}, | |
602 // {XK_F20, 'F', 'A'}, | |
603 // {XK_F21, 'F', 'B'}, | |
604 // {XK_F22, 'F', 'C'}, | |
605 // {XK_F23, 'F', 'D'}, | |
606 // {XK_F24, 'F', 'E'}, | |
607 // {XK_F25, 'F', 'F'}, | |
608 // {XK_F26, 'F', 'G'}, | |
609 // {XK_F27, 'F', 'H'}, | |
610 // {XK_F28, 'F', 'I'}, | |
611 // {XK_F29, 'F', 'J'}, | |
612 // {XK_F30, 'F', 'K'}, | |
613 // {XK_F31, 'F', 'L'}, | |
614 // {XK_F32, 'F', 'M'}, | |
615 // {XK_F33, 'F', 'N'}, | |
616 // {XK_F34, 'F', 'O'}, | |
617 // {XK_F35, 'F', 'P'}, // keysymdef.h defines up to F35 | |
618 | |
619 // {XK_Help, '%', '1'}, // XK_Help | |
620 {F(B_PRINT_KEY), '%', '9'}, | |
621 | |
622 #if 0 | |
623 // Keypad keys: | |
624 {F(0x48), 'k', 'l'}, // XK_KP_Left | |
625 {F(0x4A), 'k', 'r'}, // XK_KP_Right | |
626 {F(0x38), 'k', 'u'}, // XK_KP_Up | |
627 {F(0x59), 'k', 'd'}, // XK_KP_Down | |
628 {F(0x64), 'k', 'I'}, // XK_KP_Insert | |
629 {F(0x65), 'k', 'D'}, // XK_KP_Delete | |
630 {F(0x37), 'k', 'h'}, // XK_KP_Home | |
631 {F(0x58), '@', '7'}, // XK_KP_End | |
632 {F(0x39), 'k', 'P'}, // XK_KP_Prior | |
633 {F(0x60), 'k', 'N'}, // XK_KP_Next | |
634 {F(0x49), '&', '8'}, // XK_Undo, keypad 5 | |
635 #endif | |
636 | |
637 // End of list marker: | |
638 {0, 0, 0} | |
639 }; | |
640 | |
641 #define NUM_SPECIAL_KEYS (sizeof(special_keys)/sizeof(special_keys[0])) | |
642 | |
643 // ---------------- VimApp ---------------- | |
644 | |
645 static void | |
646 docd(BPath &path) | |
647 { | |
648 mch_chdir((char *)path.Path()); | |
649 // Do this to get the side effects of a :cd command | |
650 do_cmdline_cmd((char_u *)"cd ."); | |
651 } | |
652 | |
653 static void | |
654 drop_callback(void *cookie) | |
655 { | |
656 // TODO here we could handle going to a specific position in the dropped | |
657 // file (see src/gui_mac.c) | |
658 // Update the screen display | |
659 update_screen(NOT_VALID); | |
660 } | |
661 | |
662 // Really handle dropped files and folders. | |
663 static void | |
664 RefsReceived(BMessage *m, bool changedir) | |
665 { | |
666 uint32 type; | |
667 int32 count; | |
668 | |
669 m->PrintToStream(); | |
670 switch (m->what) { | |
671 case B_REFS_RECEIVED: | |
672 case B_SIMPLE_DATA: | |
673 m->GetInfo("refs", &type, &count); | |
674 if (type != B_REF_TYPE) | |
675 goto bad; | |
676 break; | |
677 case B_ARGV_RECEIVED: | |
678 m->GetInfo("argv", &type, &count); | |
679 if (type != B_STRING_TYPE) | |
680 goto bad; | |
681 if (changedir) { | |
682 char *dirname; | |
683 if (m->FindString("cwd", (const char **) &dirname) == B_OK) { | |
684 chdir(dirname); | |
685 do_cmdline_cmd((char_u *)"cd ."); | |
686 } | |
687 } | |
688 break; | |
689 default: | |
690 bad: | |
691 /*fprintf(stderr, "bad!\n"); */ | |
692 delete m; | |
693 return; | |
694 } | |
695 | |
696 #ifdef FEAT_VISUAL | |
697 reset_VIsual(); | |
698 #endif | |
699 | |
700 char_u **fnames; | |
701 fnames = (char_u **) alloc(count * sizeof(char_u *)); | |
702 int fname_index = 0; | |
703 | |
704 switch (m->what) { | |
705 case B_REFS_RECEIVED: | |
706 case B_SIMPLE_DATA: | |
707 // fprintf(stderr, "case B_REFS_RECEIVED\n"); | |
708 for (int i = 0; i < count; ++i) | |
709 { | |
710 entry_ref ref; | |
711 if (m->FindRef("refs", i, &ref) == B_OK) { | |
712 BEntry entry(&ref, false); | |
713 BPath path; | |
714 entry.GetPath(&path); | |
715 | |
716 // Change to parent directory? | |
717 if (changedir) { | |
718 BPath parentpath; | |
719 path.GetParent(&parentpath); | |
720 docd(parentpath); | |
721 } | |
722 | |
723 // Is it a directory? If so, cd into it. | |
724 BDirectory bdir(&ref); | |
725 if (bdir.InitCheck() == B_OK) { | |
726 // don't cd if we already did it | |
727 if (!changedir) | |
728 docd(path); | |
729 } else { | |
730 mch_dirname(IObuff, IOSIZE); | |
731 char_u *fname = shorten_fname((char_u *)path.Path(), IObuff); | |
732 if (fname == NULL) | |
733 fname = (char_u *)path.Path(); | |
734 fnames[fname_index++] = vim_strsave(fname); | |
735 // fprintf(stderr, "%s\n", fname); | |
736 } | |
737 | |
738 // Only do it for the first file/dir | |
739 changedir = false; | |
740 } | |
741 } | |
742 break; | |
743 case B_ARGV_RECEIVED: | |
744 // fprintf(stderr, "case B_ARGV_RECEIVED\n"); | |
745 for (int i = 1; i < count; ++i) | |
746 { | |
747 char *fname; | |
748 | |
749 if (m->FindString("argv", i, (const char **) &fname) == B_OK) { | |
750 fnames[fname_index++] = vim_strsave((char_u *)fname); | |
751 } | |
752 } | |
753 break; | |
754 default: | |
755 // fprintf(stderr, "case default\n"); | |
756 break; | |
757 } | |
758 | |
759 delete m; | |
760 | |
761 // Handle the drop, :edit to get to the file | |
762 if (fname_index > 0) { | |
763 handle_drop(fname_index, fnames, FALSE, drop_callback, NULL); | |
764 | |
765 setcursor(); | |
766 out_flush(); | |
767 } else { | |
768 vim_free(fnames); | |
769 } | |
770 } | |
771 | |
772 VimApp::VimApp(const char *appsig): | |
773 BApplication(appsig), | |
774 fFilePanelSem(-1), | |
775 fFilePanel(NULL) | |
776 { | |
777 } | |
778 | |
779 VimApp::~VimApp() | |
780 { | |
781 } | |
782 | |
783 void | |
784 VimApp::ReadyToRun() | |
785 { | |
786 /* | |
787 * Apparently signals are inherited by the created thread - | |
788 * disable the most annoying ones. | |
789 */ | |
790 signal(SIGINT, SIG_IGN); | |
791 signal(SIGQUIT, SIG_IGN); | |
792 } | |
793 | |
794 void | |
795 VimApp::ArgvReceived(int32 arg_argc, char **arg_argv) | |
796 { | |
797 if (!IsLaunching()) { | |
798 /* | |
799 * This can happen if we are set to Single or Exclusive | |
800 * Launch. Be nice and open the file(s). | |
801 */ | |
802 if (gui.vimWindow) | |
803 gui.vimWindow->Minimize(false); | |
804 BMessage *m = CurrentMessage(); | |
805 DetachCurrentMessage(); | |
806 SendRefs(m, true); | |
807 } | |
808 } | |
809 | |
810 void | |
811 VimApp::RefsReceived(BMessage *m) | |
812 { | |
813 // Horrible hack!!! XXX XXX XXX | |
814 // The real problem is that b_start_ffc is set too late for | |
815 // the initial empty buffer. As a result the window will be | |
816 // split instead of abandoned. | |
817 int limit = 15; | |
818 while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0)) | |
819 snooze(100000); // 0.1 s | |
820 if (gui.vimWindow) | |
821 gui.vimWindow->Minimize(false); | |
822 DetachCurrentMessage(); | |
823 SendRefs(m, true); | |
824 } | |
825 | |
826 /* | |
827 * Pass a BMessage on to the main() thread. | |
828 * Caller must have detached the message. | |
829 */ | |
830 void | |
831 VimApp::SendRefs(BMessage *m, bool changedir) | |
832 { | |
833 VimRefsMsg rm; | |
834 rm.message = m; | |
835 rm.changedir = changedir; | |
836 | |
837 write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm)); | |
838 // calls ::RefsReceived | |
839 } | |
840 | |
841 void | |
842 VimApp::MessageReceived(BMessage *m) | |
843 { | |
844 switch (m->what) { | |
845 case 'save': | |
846 { | |
847 entry_ref refDirectory; | |
848 m->FindRef("directory", &refDirectory); | |
849 fBrowsedPath.SetTo(&refDirectory); | |
850 BString strName; | |
851 m->FindString("name", &strName); | |
852 fBrowsedPath.Append(strName.String()); | |
853 } | |
854 break; | |
855 case 'open': | |
856 { | |
857 entry_ref ref; | |
858 m->FindRef("refs", &ref); | |
859 fBrowsedPath.SetTo(&ref); | |
860 } | |
861 break; | |
862 case B_CANCEL: | |
863 { | |
864 BFilePanel *panel; | |
865 m->FindPointer("source", (void**)&panel); | |
866 if(fFilePanelSem != -1 && panel == fFilePanel) | |
867 { | |
868 delete_sem(fFilePanelSem); | |
869 fFilePanelSem = -1; | |
870 } | |
871 | |
872 } | |
873 break; | |
874 default: | |
875 Inherited::MessageReceived(m); | |
876 break; | |
877 } | |
878 } | |
879 | |
880 bool | |
881 VimApp::QuitRequested() | |
882 { | |
883 (void)Inherited::QuitRequested(); | |
884 return false; | |
885 } | |
886 | |
887 // ---------------- VimWindow ---------------- | |
888 | |
889 VimWindow::VimWindow(): | |
890 BWindow(BRect(40, 40, 150, 150), | |
891 "Vim", | |
892 B_TITLED_WINDOW, | |
893 0, | |
894 B_CURRENT_WORKSPACE) | |
895 | |
896 { | |
897 init(); | |
898 } | |
899 | |
900 VimWindow::~VimWindow() | |
901 { | |
902 if (formView) { | |
903 RemoveChild(formView); | |
904 delete formView; | |
905 } | |
906 gui.vimWindow = NULL; | |
907 } | |
908 | |
909 void | |
910 VimWindow::init() | |
911 { | |
912 // Attach the VimFormView | |
913 formView = new VimFormView(Bounds()); | |
914 if (formView != NULL) { | |
915 AddChild(formView); | |
916 } | |
917 } | |
918 | |
919 #if 0 // disabled in zeta patch | |
920 void | |
921 VimWindow::DispatchMessage(BMessage *m, BHandler *h) | |
922 { | |
923 /* | |
924 * Route B_MOUSE_UP messages to MouseUp(), in | |
925 * a manner that should be compatible with the | |
926 * intended future system behaviour. | |
927 */ | |
928 switch (m->what) { | |
929 case B_MOUSE_UP: | |
930 // if (!h) h = PreferredHandler(); | |
931 // gcc isn't happy without this extra set of braces, complains about | |
932 // jump to case label crosses init of 'class BView * v' | |
933 // richard@whitequeen.com jul 99 | |
934 { | |
935 BView *v = dynamic_cast<BView *>(h); | |
936 if (v) { | |
937 // m->PrintToStream(); | |
938 BPoint where; | |
939 m->FindPoint("where", &where); | |
940 v->MouseUp(where); | |
941 } else { | |
942 Inherited::DispatchMessage(m, h); | |
943 } | |
944 } | |
945 break; | |
946 default: | |
947 Inherited::DispatchMessage(m, h); | |
948 } | |
949 } | |
950 #endif | |
951 | |
952 void | |
953 VimWindow::WindowActivated(bool active) | |
954 { | |
955 Inherited::WindowActivated(active); | |
956 // the textArea gets the keyboard action | |
957 if (active && gui.vimTextArea) | |
958 gui.vimTextArea->MakeFocus(true); | |
959 | |
960 struct VimFocusMsg fm; | |
961 fm.active = active; | |
962 | |
963 write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm)); | |
964 } | |
965 | |
966 bool | |
967 VimWindow::QuitRequested() | |
968 { | |
969 struct VimKeyMsg km; | |
970 km.length = 5; | |
971 memcpy((char *)km.chars, "\033:qa\r", km.length); | |
972 km.csi_escape = false; | |
973 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); | |
974 return false; | |
975 } | |
976 | |
977 // ---------------- VimFormView ---------------- | |
978 | |
979 VimFormView::VimFormView(BRect frame): | |
980 BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES, | |
981 B_WILL_DRAW | B_FRAME_EVENTS), | |
982 menuBar(NULL), | |
983 #ifdef FEAT_TOOLBAR | |
984 toolBar(NULL), | |
985 #endif | |
986 #ifdef FEAT_GUI_TABLINE | |
987 // showingTabLine(false), | |
988 tabLine(NULL), | |
989 #endif | |
990 textArea(NULL) | |
991 { | |
992 init(frame); | |
993 } | |
994 | |
995 VimFormView::~VimFormView() | |
996 { | |
997 if (menuBar) { | |
998 RemoveChild(menuBar); | |
999 #ifdef never | |
1000 // deleting the menuBar leads to SEGV on exit | |
1001 // richard@whitequeen.com Jul 99 | |
1002 delete menuBar; | |
1003 #endif | |
1004 } | |
1005 | |
1006 #ifdef FEAT_TOOLBAR | |
1007 delete toolBar; | |
1008 #endif | |
1009 | |
1010 #ifdef FEAT_GUI_TABLINE | |
1011 delete tabLine; | |
1012 #endif | |
1013 | |
1014 if (textArea) { | |
1015 RemoveChild(textArea); | |
1016 delete textArea; | |
1017 } | |
1018 gui.vimForm = NULL; | |
1019 } | |
1020 | |
1021 void | |
1022 VimFormView::init(BRect frame) | |
1023 { | |
1024 menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN), | |
1025 "VimMenuBar"); | |
1026 | |
1027 AddChild(menuBar); | |
1028 | |
1029 #ifdef FEAT_TOOLBAR | |
1030 toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar"); | |
1031 toolBar->PrepareButtonBitmaps(); | |
1032 AddChild(toolBar); | |
1033 #endif | |
1034 | |
1035 #ifdef FEAT_GUI_TABLINE | |
1036 tabLine = new VimTabLine(BRect(0,0,0,0)); | |
1037 // tabLine->PrepareButtonBitmaps(); | |
1038 AddChild(tabLine); | |
1039 #endif | |
1040 | |
1041 BRect remaining = frame; | |
1042 textArea = new VimTextAreaView(remaining); | |
1043 AddChild(textArea); | |
1044 // The textArea will be resized later when menus are added | |
1045 | |
1046 gui.vimForm = this; | |
1047 } | |
1048 | |
1049 #ifdef FEAT_TOOLBAR | |
1050 float | |
1051 VimFormView::ToolbarHeight() const | |
1052 { | |
1053 return toolBar ? toolBar->ToolbarHeight() : 0.; | |
1054 } | |
1055 #endif | |
1056 | |
1057 #ifdef FEAT_GUI_TABLINE | |
1058 float | |
1059 VimFormView::TablineHeight() const | |
1060 { | |
1061 return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.; | |
1062 } | |
1063 #endif | |
1064 | |
1065 void | |
1066 VimFormView::AllAttached() | |
1067 { | |
1068 /* | |
1069 * Apparently signals are inherited by the created thread - | |
1070 * disable the most annoying ones. | |
1071 */ | |
1072 signal(SIGINT, SIG_IGN); | |
1073 signal(SIGQUIT, SIG_IGN); | |
1074 | |
1075 if (menuBar && textArea) { | |
1076 /* | |
1077 * Resize the textArea to fill the space left over by the menu. | |
1078 * This is somewhat futile since it will be done again once | |
1079 * menus are added to the menu bar. | |
1080 */ | |
1081 BRect remaining = Bounds(); | |
1082 | |
1083 #ifdef FEAT_MENU | |
1084 remaining.top += MenuHeight(); | |
1085 menuBar->ResizeTo(remaining.right, remaining.top); | |
1086 gui.menu_height = (int) MenuHeight(); | |
1087 #endif | |
1088 | |
1089 #ifdef FEAT_TOOLBAR | |
1090 toolBar->MoveTo(remaining.left, remaining.top); | |
1091 toolBar->ResizeTo(remaining.right, ToolbarHeight()); | |
1092 remaining.top += ToolbarHeight(); | |
1093 gui.toolbar_height = ToolbarHeight(); | |
1094 #endif | |
1095 | |
1096 #ifdef FEAT_GUI_TABLINE | |
1097 tabLine->MoveTo(remaining.left, remaining.top); | |
1098 tabLine->ResizeTo(remaining.right + 1, TablineHeight()); | |
1099 remaining.top += TablineHeight(); | |
1100 gui.tabline_height = TablineHeight(); | |
1101 #endif | |
1102 | |
1103 textArea->ResizeTo(remaining.Width(), remaining.Height()); | |
1104 textArea->MoveTo(remaining.left, remaining.top); | |
1105 } | |
1106 | |
1107 | |
1108 Inherited::AllAttached(); | |
1109 } | |
1110 | |
1111 void | |
1112 VimFormView::FrameResized(float new_width, float new_height) | |
1113 { | |
1114 struct VimResizeMsg sm; | |
1115 int adjust_h, adjust_w; | |
1116 | |
1117 new_width += 1; // adjust from width to number of pixels occupied | |
1118 new_height += 1; | |
1119 | |
1120 sm.width = (int) new_width; | |
1121 sm.height = (int) new_height; | |
1122 adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width; | |
1123 adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height; | |
1124 | |
1125 if (adjust_w > 0 || adjust_h > 0) { | |
1126 sm.width -= adjust_w; | |
1127 sm.height -= adjust_h; | |
1128 } | |
1129 | |
1130 write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm)); | |
1131 // calls gui_resize_shell(new_width, new_height); | |
1132 | |
1133 return; | |
1134 | |
1135 /* | |
1136 * The area below the vertical scrollbar is erased to the colour | |
1137 * set with SetViewColor() automatically, because we had set | |
1138 * B_WILL_DRAW. Resizing the window tight around the vertical | |
1139 * scroll bar also helps to avoid debris. | |
1140 */ | |
1141 } | |
1142 | |
1143 // ---------------- VimTextAreaView ---------------- | |
1144 | |
1145 VimTextAreaView::VimTextAreaView(BRect frame): | |
1146 BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES, | |
1147 #ifdef FEAT_MBYTE_IME | |
1148 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE), | |
1149 #else | |
1150 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), | |
1151 #endif | |
1152 mouseDragEventCount(0) | |
1153 { | |
1154 #ifdef FEAT_MBYTE_IME | |
1155 IMData.messenger = NULL; | |
1156 IMData.message = NULL; | |
1157 #endif | |
1158 init(frame); | |
1159 } | |
1160 | |
1161 VimTextAreaView::~VimTextAreaView() | |
1162 { | |
1163 gui.vimTextArea = NULL; | |
1164 } | |
1165 | |
1166 void | |
1167 VimTextAreaView::init(BRect frame) | |
1168 { | |
1169 // set up global var for fast access | |
1170 gui.vimTextArea = this; | |
1171 | |
1172 /* | |
1173 * Tell the app server not to erase the view: we will | |
1174 * fill it in completely by ourselves. | |
1175 * (Does this really work? Even if not, it won't harm either.) | |
1176 */ | |
1177 SetViewColor(B_TRANSPARENT_32_BIT); | |
1178 #define PEN_WIDTH 1 | |
1179 SetPenSize(PEN_WIDTH); | |
1180 #define W_WIDTH(curwin) 0 | |
1181 } | |
1182 | |
1183 void | |
1184 VimTextAreaView::Draw(BRect updateRect) | |
1185 { | |
1186 /* | |
1187 * XXX Other ports call here: | |
1188 * out_flush(); * make sure all output has been processed * | |
1189 * but we can't do that, since it involves too much information | |
1190 * that is owned by other threads... | |
1191 */ | |
1192 | |
1193 /* | |
1194 * No need to use gui.vimWindow->Lock(): we are locked already. | |
1195 * However, it would not hurt. | |
1196 */ | |
1197 rgb_color rgb = GUI_TO_RGB(gui.back_pixel); | |
1198 SetLowColor(rgb); | |
1199 FillRect(updateRect, B_SOLID_LOW); | |
1200 gui_redraw((int) updateRect.left, (int) updateRect.top, | |
1201 (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH)); | |
1202 | |
1203 // Clear the border areas if needed | |
1204 SetLowColor(rgb); | |
1205 | |
1206 if (updateRect.left < FILL_X(0)) // left border | |
1207 FillRect(BRect(updateRect.left, updateRect.top, | |
1208 FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW); | |
1209 if (updateRect.top < FILL_Y(0)) // top border | |
1210 FillRect(BRect(updateRect.left, updateRect.top, | |
1211 updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW); | |
1212 if (updateRect.right >= FILL_X(Columns)) // right border | |
1213 FillRect(BRect(FILL_X((int)Columns), updateRect.top, | |
1214 updateRect.right, updateRect.bottom), B_SOLID_LOW); | |
1215 if (updateRect.bottom >= FILL_Y(Rows)) // bottom border | |
1216 FillRect(BRect(updateRect.left, FILL_Y((int)Rows), | |
1217 updateRect.right, updateRect.bottom), B_SOLID_LOW); | |
1218 | |
1219 #ifdef FEAT_MBYTE_IME | |
1220 DrawIMString(); | |
1221 #endif | |
1222 } | |
1223 | |
1224 void | |
1225 VimTextAreaView::KeyDown(const char *bytes, int32 numBytes) | |
1226 { | |
1227 struct VimKeyMsg km; | |
1228 char_u *dest = km.chars; | |
1229 | |
1230 bool canHaveVimModifiers = false; | |
1231 | |
1232 BMessage *msg = Window()->CurrentMessage(); | |
1233 assert(msg); | |
1234 // msg->PrintToStream(); | |
1235 | |
1236 /* | |
1237 * Convert special keys to Vim codes. | |
1238 * I think it is better to do it in the window thread | |
1239 * so we use at least a little bit of the potential | |
1240 * of our 2 CPUs. Besides, due to the fantastic mapping | |
1241 * of special keys to UTF-8, we have quite some work to | |
1242 * do... | |
1243 * TODO: I'm not quite happy with detection of special | |
1244 * keys. Perhaps I should use scan codes after all... | |
1245 */ | |
1246 if (numBytes > 1) { | |
1247 // This cannot be a special key | |
1248 if (numBytes > KEY_MSG_BUFSIZ) | |
1249 numBytes = KEY_MSG_BUFSIZ; // should never happen... ??? | |
1250 km.length = numBytes; | |
1251 memcpy((char *)dest, bytes, numBytes); | |
1252 km.csi_escape = true; | |
1253 } else { | |
1254 int32 scancode = 0; | |
1255 msg->FindInt32("key", &scancode); | |
1256 | |
1257 int32 beModifiers = 0; | |
1258 msg->FindInt32("modifiers", &beModifiers); | |
1259 | |
1260 char_u string[3]; | |
1261 int len = 0; | |
1262 km.length = 0; | |
1263 | |
1264 /* | |
1265 * For normal, printable ASCII characters, don't look them up | |
1266 * to check if they might be a special key. They aren't. | |
1267 */ | |
1268 assert(B_BACKSPACE <= 0x20); | |
1269 assert(B_DELETE == 0x7F); | |
1270 if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) && | |
1271 numBytes == 1) { | |
1272 /* | |
1273 * Due to the great nature of Be's mapping of special keys, | |
1274 * viz. into the range of the control characters, | |
1275 * we can only be sure it is *really* a special key if | |
1276 * if it is special without using ctrl. So, only if ctrl is | |
1277 * used, we need to check it unmodified. | |
1278 */ | |
1279 if (beModifiers & B_CONTROL_KEY) { | |
1280 int index = keyMap->normal_map[scancode]; | |
1281 int newNumBytes = keyMapChars[index]; | |
1282 char_u *newBytes = (char_u *)&keyMapChars[index + 1]; | |
1283 | |
1284 /* | |
1285 * Check if still special without the control key. | |
1286 * This is needed for BACKSPACE: that key does produce | |
1287 * different values with modifiers (DEL). | |
1288 * Otherwise we could simply have checked for equality. | |
1289 */ | |
1290 if (newNumBytes != 1 || (*newBytes > 0x20 && | |
1291 *newBytes != 0x7F )) { | |
1292 goto notspecial; | |
1293 } | |
1294 bytes = (char *)newBytes; | |
1295 } | |
1296 canHaveVimModifiers = true; | |
1297 | |
1298 uint16 beoskey; | |
1299 int first, last; | |
1300 | |
1301 /* | |
1302 * If numBytes == 0 that probably always indicates a special key. | |
1303 * (does not happen yet) | |
1304 */ | |
1305 if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) { | |
1306 beoskey = F(scancode); | |
1307 first = FIRST_FUNCTION_KEY; | |
1308 last = NUM_SPECIAL_KEYS; | |
1309 } else if (*bytes == '\n' && scancode == 0x47) { | |
1310 // remap the (non-keypad) ENTER key from \n to \r. | |
1311 string[0] = '\r'; | |
1312 len = 1; | |
1313 first = last = 0; | |
1314 } else { | |
1315 beoskey = K(bytes[0]); | |
1316 first = 0; | |
1317 last = FIRST_FUNCTION_KEY; | |
1318 } | |
1319 | |
1320 for (int i = first; i < last; i++) { | |
1321 if (special_keys[i].BeKeys == beoskey) { | |
1322 string[0] = CSI; | |
1323 string[1] = special_keys[i].vim_code0; | |
1324 string[2] = special_keys[i].vim_code1; | |
1325 len = 3; | |
1326 } | |
1327 } | |
1328 } | |
1329 notspecial: | |
1330 if (len == 0) { | |
1331 string[0] = bytes[0]; | |
1332 len = 1; | |
1333 } | |
1334 | |
1335 // Special keys (and a few others) may have modifiers | |
1336 #if 0 | |
1337 if (len == 3 || | |
1338 bytes[0] == B_SPACE || bytes[0] == B_TAB || | |
1339 bytes[0] == B_RETURN || bytes[0] == '\r' || | |
1340 bytes[0] == B_ESCAPE) | |
1341 #else | |
1342 if (canHaveVimModifiers) | |
1343 #endif | |
1344 { | |
1345 int modifiers; | |
1346 modifiers = 0; | |
1347 if (beModifiers & B_SHIFT_KEY) | |
1348 modifiers |= MOD_MASK_SHIFT; | |
1349 if (beModifiers & B_CONTROL_KEY) | |
1350 modifiers |= MOD_MASK_CTRL; | |
1351 if (beModifiers & B_OPTION_KEY) | |
1352 modifiers |= MOD_MASK_ALT; | |
1353 | |
1354 /* | |
1355 * For some keys a shift modifier is translated into another key | |
1356 * code. Do we need to handle the case where len != 1 and | |
1357 * string[0] != CSI? (Not for BeOS, since len == 3 implies | |
1358 * string[0] == CSI...) | |
1359 */ | |
1360 int key; | |
1361 if (string[0] == CSI && len == 3) | |
1362 key = TO_SPECIAL(string[1], string[2]); | |
1363 else | |
1364 key = string[0]; | |
1365 key = simplify_key(key, &modifiers); | |
1366 if (IS_SPECIAL(key)) | |
1367 { | |
1368 string[0] = CSI; | |
1369 string[1] = K_SECOND(key); | |
1370 string[2] = K_THIRD(key); | |
1371 len = 3; | |
1372 } | |
1373 else | |
1374 { | |
1375 string[0] = key; | |
1376 len = 1; | |
1377 } | |
1378 | |
1379 if (modifiers) | |
1380 { | |
1381 *dest++ = CSI; | |
1382 *dest++ = KS_MODIFIER; | |
1383 *dest++ = modifiers; | |
1384 km.length = 3; | |
1385 } | |
1386 } | |
1387 memcpy((char *)dest, string, len); | |
1388 km.length += len; | |
1389 km.csi_escape = false; | |
1390 } | |
1391 | |
1392 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); | |
1393 | |
1394 /* | |
1395 * blank out the pointer if necessary | |
1396 */ | |
1397 if (p_mh && !gui.pointer_hidden) | |
1398 { | |
1399 guiBlankMouse(true); | |
1400 gui.pointer_hidden = TRUE; | |
1401 } | |
1402 } | |
1403 void | |
1404 VimTextAreaView::guiSendMouseEvent( | |
1405 int button, | |
1406 int x, | |
1407 int y, | |
1408 int repeated_click, | |
1409 int_u modifiers) | |
1410 { | |
1411 VimMouseMsg mm; | |
1412 | |
1413 mm.button = button; | |
1414 mm.x = x; | |
1415 mm.y = y; | |
1416 mm.repeated_click = repeated_click; | |
1417 mm.modifiers = modifiers; | |
1418 | |
1419 write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm)); | |
1420 // calls gui_send_mouse_event() | |
1421 | |
1422 /* | |
1423 * if our pointer is currently hidden, then we should show it. | |
1424 */ | |
1425 if (gui.pointer_hidden) | |
1426 { | |
1427 guiBlankMouse(false); | |
1428 gui.pointer_hidden = FALSE; | |
1429 } | |
1430 } | |
1431 | |
1432 void | |
1433 VimTextAreaView::guiMouseMoved( | |
1434 int x, | |
1435 int y) | |
1436 { | |
1437 VimMouseMovedMsg mm; | |
1438 | |
1439 mm.x = x; | |
1440 mm.y = y; | |
1441 | |
1442 write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm)); | |
1443 | |
1444 if (gui.pointer_hidden) | |
1445 { | |
1446 guiBlankMouse(false); | |
1447 gui.pointer_hidden = FALSE; | |
1448 } | |
1449 } | |
1450 | |
1451 void | |
1452 VimTextAreaView::guiBlankMouse(bool should_hide) | |
1453 { | |
1454 if (should_hide) { | |
1455 // gui.vimApp->HideCursor(); | |
1456 gui.vimApp->ObscureCursor(); | |
1457 /* | |
1458 * ObscureCursor() would even be easier, but then | |
1459 * Vim's idea of mouse visibility does not necessarily | |
1460 * correspond to reality. | |
1461 */ | |
1462 } else { | |
1463 // gui.vimApp->ShowCursor(); | |
1464 } | |
1465 } | |
1466 | |
1467 int_u | |
1468 VimTextAreaView::mouseModifiersToVim(int32 beModifiers) | |
1469 { | |
1470 int_u vim_modifiers = 0x0; | |
1471 | |
1472 if (beModifiers & B_SHIFT_KEY) | |
1473 vim_modifiers |= MOUSE_SHIFT; | |
1474 if (beModifiers & B_CONTROL_KEY) | |
1475 vim_modifiers |= MOUSE_CTRL; | |
1476 if (beModifiers & B_OPTION_KEY) // Alt or Meta key | |
1477 vim_modifiers |= MOUSE_ALT; | |
1478 | |
1479 return vim_modifiers; | |
1480 } | |
1481 | |
1482 void | |
1483 VimTextAreaView::MouseDown(BPoint point) | |
1484 { | |
1485 BMessage *m = Window()->CurrentMessage(); | |
1486 assert(m); | |
1487 | |
1488 int32 buttons = 0; | |
1489 m->FindInt32("buttons", &buttons); | |
1490 | |
1491 int vimButton; | |
1492 | |
1493 if (buttons & B_PRIMARY_MOUSE_BUTTON) | |
1494 vimButton = MOUSE_LEFT; | |
1495 else if (buttons & B_SECONDARY_MOUSE_BUTTON) | |
1496 vimButton = MOUSE_RIGHT; | |
1497 else if (buttons & B_TERTIARY_MOUSE_BUTTON) | |
1498 vimButton = MOUSE_MIDDLE; | |
1499 else | |
1500 return; // Unknown button | |
1501 | |
1502 vimMouseButton = 1; // don't care which one | |
1503 | |
1504 // Handle multiple clicks | |
1505 int32 clicks = 0; | |
1506 m->FindInt32("clicks", &clicks); | |
1507 | |
1508 int32 modifiers = 0; | |
1509 m->FindInt32("modifiers", &modifiers); | |
1510 | |
1511 vimMouseModifiers = mouseModifiersToVim(modifiers); | |
1512 | |
1513 guiSendMouseEvent(vimButton, point.x, point.y, | |
1514 clicks > 1 /* = repeated_click*/, vimMouseModifiers); | |
1515 } | |
1516 | |
1517 void | |
1518 VimTextAreaView::MouseUp(BPoint point) | |
1519 { | |
1520 vimMouseButton = 0; | |
1521 | |
1522 BMessage *m = Window()->CurrentMessage(); | |
1523 assert(m); | |
1524 // m->PrintToStream(); | |
1525 | |
1526 int32 modifiers = 0; | |
1527 m->FindInt32("modifiers", &modifiers); | |
1528 | |
1529 vimMouseModifiers = mouseModifiersToVim(modifiers); | |
1530 | |
1531 guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y, | |
1532 0 /* = repeated_click*/, vimMouseModifiers); | |
1533 | |
1534 Inherited::MouseUp(point); | |
1535 } | |
1536 | |
1537 void | |
1538 VimTextAreaView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) | |
1539 { | |
1540 /* | |
1541 * if our pointer is currently hidden, then we should show it. | |
1542 */ | |
1543 if (gui.pointer_hidden) | |
1544 { | |
1545 guiBlankMouse(false); | |
1546 gui.pointer_hidden = FALSE; | |
1547 } | |
1548 | |
1549 if (!vimMouseButton) { // could also check m->"buttons" | |
1550 guiMouseMoved(point.x, point.y); | |
1551 return; | |
1552 } | |
1553 | |
1554 atomic_add(&mouseDragEventCount, 1); | |
1555 | |
1556 // Don't care much about "transit" | |
1557 guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers); | |
1558 } | |
1559 | |
1560 void | |
1561 VimTextAreaView::MessageReceived(BMessage *m) | |
1562 { | |
1563 switch (m->what) { | |
1564 case 'menu': | |
1565 { | |
1566 VimMenuMsg mm; | |
1567 mm.guiMenu = NULL; // in case no pointer in msg | |
1568 m->FindPointer("VimMenu", (void **)&mm.guiMenu); | |
1569 write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm)); | |
1570 } | |
1571 break; | |
1572 case B_MOUSE_WHEEL_CHANGED: | |
1573 { | |
1574 VimScrollBar* scb = curwin->w_scrollbars[1].id; | |
1575 float small=0, big=0, dy=0; | |
1576 m->FindFloat("be:wheel_delta_y", &dy); | |
1577 scb->GetSteps(&small, &big); | |
1578 scb->SetValue(scb->Value()+small*dy*3); | |
1579 scb->ValueChanged(scb->Value()); | |
1580 #if 0 | |
1581 scb = curwin->w_scrollbars[0].id; | |
1582 scb->GetSteps(&small, &big); | |
1583 scb->SetValue(scb->Value()+small*dy); | |
1584 scb->ValueChanged(scb->Value()); | |
1585 #endif | |
1586 } | |
1587 break; | |
1588 #ifdef FEAT_MBYTE_IME | |
1589 case B_INPUT_METHOD_EVENT: | |
1590 { | |
1591 int32 opcode; | |
1592 m->FindInt32("be:opcode", &opcode); | |
1593 switch(opcode) | |
1594 { | |
1595 case B_INPUT_METHOD_STARTED: | |
1596 if(!IMData.messenger) delete IMData.messenger; | |
1597 IMData.messenger = new BMessenger(); | |
1598 m->FindMessenger("be:reply_to", IMData.messenger); | |
1599 break; | |
1600 case B_INPUT_METHOD_CHANGED: | |
1601 { | |
1602 BString str; | |
1603 bool confirmed; | |
1604 if(IMData.message) *(IMData.message) = *m; | |
1605 else IMData.message = new BMessage(*m); | |
1606 DrawIMString(); | |
1607 m->FindBool("be:confirmed", &confirmed); | |
1608 if (confirmed) | |
1609 { | |
1610 m->FindString("be:string", &str); | |
1611 char_u *chars = (char_u*)str.String(); | |
1612 struct VimKeyMsg km; | |
1613 km.csi_escape = true; | |
1614 int clen; | |
1615 int i = 0; | |
1616 while (i < str.Length()) | |
1617 { | |
1618 clen = utf_ptr2len(chars+i); | |
1619 memcpy(km.chars, chars+i, clen); | |
1620 km.length = clen; | |
1621 write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); | |
1622 i += clen; | |
1623 } | |
1624 } | |
1625 } | |
1626 break; | |
1627 case B_INPUT_METHOD_LOCATION_REQUEST: | |
1628 { | |
1629 BMessage msg(B_INPUT_METHOD_EVENT); | |
1630 msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST); | |
1631 msg.AddPoint("be:location_reply", IMData.location); | |
1632 msg.AddFloat("be:height_reply", FILL_Y(1)); | |
1633 IMData.messenger->SendMessage(&msg); | |
1634 } | |
1635 break; | |
1636 case B_INPUT_METHOD_STOPPED: | |
1637 delete IMData.messenger; | |
1638 delete IMData.message; | |
1639 IMData.messenger = NULL; | |
1640 IMData.message = NULL; | |
1641 break; | |
1642 } | |
1643 } | |
1644 // TODO: sz: break here??? | |
1645 #endif | |
1646 default: | |
1647 if (m->WasDropped()) { | |
1648 BWindow *w = Window(); | |
1649 w->DetachCurrentMessage(); | |
1650 w->Minimize(false); | |
1651 VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0); | |
1652 } else { | |
1653 Inherited::MessageReceived(m); | |
1654 } | |
1655 break; | |
1656 } | |
1657 } | |
1658 | |
1659 int | |
1660 VimTextAreaView::mchInitFont(char_u *name) | |
1661 { | |
1662 VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1); | |
1663 if(newFont != NOFONT) { | |
1664 gui.norm_font = (GuiFont)newFont; | |
1665 gui_mch_set_font((GuiFont)newFont); | |
1666 if (name && STRCMP(name, "*") != 0) | |
1667 hl_set_font_name(name); | |
1668 | |
1669 SetDrawingMode(B_OP_COPY); | |
1670 | |
1671 /* | |
1672 * Try to load other fonts for bold, italic, and bold-italic. | |
1673 * We should also try to work out what font to use for these when they are | |
1674 * not specified by X resources, but we don't yet. | |
1675 */ | |
1676 return OK; | |
1677 } | |
1678 return FAIL; | |
1679 } | |
1680 | |
1681 void | |
1682 VimTextAreaView::mchDrawString(int row, int col, char_u *s, int len, int flags) | |
1683 { | |
1684 /* | |
1685 * First we must erase the area, because DrawString won't do | |
1686 * that for us. XXX Most of the time this is a waste of effort | |
1687 * since the bachground has been erased already... DRAW_TRANSP | |
1688 * should be set when appropriate!!! | |
1689 * (Rectangles include the bottom and right edge) | |
1690 */ | |
1691 if (!(flags & DRAW_TRANSP)) { | |
1692 int cells; | |
1693 cells = 0; | |
1694 for(int i=0; i<len; i++) { | |
1695 int cn = utf_ptr2cells((char_u *)(s+i)); | |
1696 if(cn<4) cells += cn; | |
1697 } | |
1698 | |
1699 BRect r(FILL_X(col), FILL_Y(row), | |
1700 FILL_X(col + cells) - PEN_WIDTH, FILL_Y(row + 1) - PEN_WIDTH); | |
1701 FillRect(r, B_SOLID_LOW); | |
1702 } | |
1703 | |
1704 BFont font; | |
1705 this->GetFont(&font); | |
1706 if(!font.IsFixed()) | |
1707 { | |
1708 char* p = (char*)s; | |
1709 int32 clen, lastpos = 0; | |
1710 BPoint where; | |
1711 int cells; | |
1712 while((p - (char*)s) < len) { | |
1713 clen = utf_ptr2len((u_char*)p); | |
1714 where.Set(TEXT_X(col+lastpos), TEXT_Y(row)); | |
1715 DrawString(p, clen, where); | |
1716 if (flags & DRAW_BOLD) { | |
1717 where.x += 1.0; | |
1718 SetDrawingMode(B_OP_BLEND); | |
1719 DrawString(p, clen, where); | |
1720 SetDrawingMode(B_OP_COPY); | |
1721 } | |
1722 cells = utf_ptr2cells((char_u *)p); | |
1723 if(cells<4) lastpos += cells; | |
1724 else lastpos++; | |
1725 p += clen; | |
1726 } | |
1727 } | |
1728 else | |
1729 { | |
1730 BPoint where(TEXT_X(col), TEXT_Y(row)); | |
1731 DrawString((char*)s, len, where); | |
1732 if (flags & DRAW_BOLD) { | |
1733 where.x += 1.0; | |
1734 SetDrawingMode(B_OP_BLEND); | |
1735 DrawString((char*)s, len, where); | |
1736 SetDrawingMode(B_OP_COPY); | |
1737 } | |
1738 } | |
1739 | |
1740 if (flags & DRAW_UNDERL) { | |
1741 int cells; | |
1742 cells = 0; | |
1743 for(int i=0; i<len; i++) { | |
1744 int cn = utf_ptr2cells((char_u *)(s+i)); | |
1745 if(cn<4) cells += cn; | |
1746 } | |
1747 | |
1748 BPoint start(FILL_X(col), FILL_Y(row + 1) - PEN_WIDTH); | |
1749 BPoint end(FILL_X(col + cells) - PEN_WIDTH, start.y); | |
1750 | |
1751 StrokeLine(start, end); | |
1752 } | |
1753 } | |
1754 | |
1755 void | |
1756 VimTextAreaView::mchClearBlock( | |
1757 int row1, | |
1758 int col1, | |
1759 int row2, | |
1760 int col2) | |
1761 { | |
1762 BRect r(FILL_X(col1), FILL_Y(row1), | |
1763 FILL_X(col2 + 1) - PEN_WIDTH, FILL_Y(row2 + 1) - PEN_WIDTH); | |
1764 gui_mch_set_bg_color(gui.back_pixel); | |
1765 FillRect(r, B_SOLID_LOW); | |
1766 } | |
1767 | |
1768 void | |
1769 VimTextAreaView::mchClearAll() | |
1770 { | |
1771 gui_mch_set_bg_color(gui.back_pixel); | |
1772 FillRect(Bounds(), B_SOLID_LOW); | |
1773 } | |
1774 | |
1775 /* | |
1776 * mchDeleteLines() Lock()s the window by itself. | |
1777 */ | |
1778 void | |
1779 VimTextAreaView::mchDeleteLines(int row, int num_lines) | |
1780 { | |
1781 BRect source, dest; | |
1782 source.left = FILL_X(gui.scroll_region_left); | |
1783 source.top = FILL_Y(row + num_lines); | |
1784 source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; | |
1785 source.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH; | |
1786 | |
1787 dest.left = FILL_X(gui.scroll_region_left); | |
1788 dest.top = FILL_Y(row); | |
1789 dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; | |
1790 dest.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH; | |
1791 | |
1792 if (gui.vimWindow->Lock()) { | |
1793 // Clear one column more for when bold has spilled over | |
1794 CopyBits(source, dest); | |
1795 gui_clear_block(gui.scroll_region_bot - num_lines + 1, | |
1796 gui.scroll_region_left, | |
1797 gui.scroll_region_bot, gui.scroll_region_right); | |
1798 | |
1799 | |
1800 gui.vimWindow->Unlock(); | |
1801 /* | |
1802 * The Draw() callback will be called now if some of the source | |
1803 * bits were not in the visible region. | |
1804 */ | |
1805 } | |
1806 // gui_x11_check_copy_area(); | |
1807 // } | |
1808 } | |
1809 | |
1810 /* | |
1811 * mchInsertLines() Lock()s the window by itself. | |
1812 */ | |
1813 void | |
1814 VimTextAreaView::mchInsertLines(int row, int num_lines) | |
1815 { | |
1816 BRect source, dest; | |
1817 | |
1818 // XXX Attempt at a hack: | |
1819 gui.vimWindow->UpdateIfNeeded(); | |
1820 source.left = FILL_X(gui.scroll_region_left); | |
1821 source.top = FILL_Y(row); | |
1822 source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; | |
1823 source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH; | |
1824 | |
1825 dest.left = FILL_X(gui.scroll_region_left); | |
1826 dest.top = FILL_Y(row + num_lines); | |
1827 dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; | |
1828 dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH; | |
1829 | |
1830 if (gui.vimWindow->Lock()) { | |
1831 // Clear one column more for when bold has spilled over | |
1832 CopyBits(source, dest); | |
1833 gui_clear_block(row, gui.scroll_region_left, | |
1834 row + num_lines - 1, gui.scroll_region_right); | |
1835 | |
1836 gui.vimWindow->Unlock(); | |
1837 /* | |
1838 * The Draw() callback will be called now if some of the source | |
1839 * bits were not in the visible region. | |
1840 * However, if we scroll too fast it can't keep up and the | |
1841 * update region gets messed up. This seems to be because copying | |
1842 * un-Draw()n bits does not generate Draw() calls for the copy... | |
1843 * I moved the hack to before the CopyBits() to reduce the | |
1844 * amount of additional waiting needed. | |
1845 */ | |
1846 | |
1847 // gui_x11_check_copy_area(); | |
1848 | |
1849 } | |
1850 } | |
1851 | |
1852 #ifdef FEAT_MBYTE_IME | |
1853 /* | |
1854 * DrawIMString draws string with IMData.message. | |
1855 */ | |
1856 void VimTextAreaView::DrawIMString(void) | |
1857 { | |
1858 static const rgb_color r_highlight = {255, 152, 152, 255}, | |
1859 b_highlight = {152, 203, 255, 255}; | |
1860 BString str; | |
1861 const char* s; | |
1862 int len; | |
1863 BMessage* msg = IMData.message; | |
1864 if (!msg) | |
1865 return; | |
1866 gui_redraw_block(IMData.row, 0, | |
1867 IMData.row + IMData.count, W_WIDTH(curwin), GUI_MON_NOCLEAR); | |
1868 bool confirmed = false; | |
1869 msg->FindBool("be:confirmed", &confirmed); | |
1870 if (confirmed) | |
1871 return; | |
1872 rgb_color hcolor = HighColor(), lcolor = LowColor(); | |
1873 msg->FindString("be:string", &str); | |
1874 s = str.String(); | |
1875 len = str.Length(); | |
1876 SetHighColor(0, 0, 0); | |
1877 IMData.row = gui.row; | |
1878 IMData.col = gui.col; | |
1879 int32 sel_start = 0, sel_end = 0; | |
1880 msg->FindInt32("be:selection", 0, &sel_start); | |
1881 msg->FindInt32("be:selection", 1, &sel_end); | |
1882 int clen, cn; | |
1883 BPoint pos(IMData.col, 0); | |
1884 BRect r; | |
1885 BPoint where; | |
1886 IMData.location = ConvertToScreen( | |
1887 BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y))); | |
1888 for (int i=0; i<len; i+=clen) | |
1889 { | |
1890 cn = utf_ptr2cells((char_u *)(s+i)); | |
1891 clen = utf_ptr2len((char_u *)(s+i)); | |
1892 if (pos.x + cn > W_WIDTH(curwin)) | |
1893 { | |
1894 pos.y++; | |
1895 pos.x = 0; | |
1896 } | |
1897 if (sel_start<=i && i<sel_end) | |
1898 { | |
1899 SetLowColor(r_highlight); | |
1900 IMData.location = ConvertToScreen( | |
1901 BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y))); | |
1902 } | |
1903 else | |
1904 { | |
1905 SetLowColor(b_highlight); | |
1906 } | |
1907 r.Set(FILL_X(pos.x), FILL_Y(IMData.row + pos.y), | |
1908 FILL_X(pos.x + cn) - PEN_WIDTH, | |
1909 FILL_Y(IMData.row + pos.y + 1) - PEN_WIDTH); | |
1910 FillRect(r, B_SOLID_LOW); | |
1911 where.Set(TEXT_X(pos.x), TEXT_Y(IMData.row + pos.y)); | |
1912 DrawString((s+i), clen, where); | |
1913 pos.x += cn; | |
1914 } | |
1915 IMData.count = (int)pos.y; | |
1916 | |
1917 SetHighColor(hcolor); | |
1918 SetLowColor(lcolor); | |
1919 } | |
1920 #endif | |
1921 // ---------------- VimScrollBar ---------------- | |
1922 | |
1923 /* | |
1924 * BUG: XXX | |
1925 * It seems that BScrollBar determine their direction not from | |
1926 * "posture" but from if they are "tall" or "wide" in shape... | |
1927 * | |
1928 * Also, place them out of sight, because Vim enables them before | |
1929 * they are positioned. | |
1930 */ | |
1931 VimScrollBar::VimScrollBar(scrollbar_T *g, orientation posture): | |
1932 BScrollBar(posture == B_HORIZONTAL ? BRect(-100,-100,-10,-90) : | |
1933 BRect(-100,-100,-90,-10), | |
1934 "vim scrollbar", (BView *)NULL, | |
1935 0.0, 10.0, posture), | |
1936 ignoreValue(-1), | |
1937 scrollEventCount(0) | |
1938 { | |
1939 gsb = g; | |
1940 SetResizingMode(B_FOLLOW_NONE); | |
1941 } | |
1942 | |
1943 VimScrollBar::~VimScrollBar() | |
1944 { | |
1945 } | |
1946 | |
1947 void | |
1948 VimScrollBar::ValueChanged(float newValue) | |
1949 { | |
1950 if (ignoreValue >= 0.0 && newValue == ignoreValue) { | |
1951 ignoreValue = -1; | |
1952 return; | |
1953 } | |
1954 ignoreValue = -1; | |
1955 /* | |
1956 * We want to throttle the amount of scroll messages generated. | |
1957 * Normally I presume you won't get a new message before we've | |
1958 * handled the previous one, but because we're passing them on this | |
1959 * happens very quickly. So instead we keep a counter of how many | |
1960 * scroll events there are (or will be) in the VDCMP, and the | |
1961 * throttling happens at the receiving end. | |
1962 */ | |
1963 atomic_add(&scrollEventCount, 1); | |
1964 | |
1965 struct VimScrollBarMsg sm; | |
1966 | |
1967 sm.sb = this; | |
1968 sm.value = (long) newValue; | |
1969 sm.stillDragging = TRUE; | |
1970 | |
1971 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); | |
1972 | |
1973 // calls gui_drag_scrollbar(sb, newValue, TRUE); | |
1974 } | |
1975 | |
1976 /* | |
1977 * When the mouse goes up, report that scrolling has stopped. | |
1978 * MouseUp() is NOT called when the mouse-up occurs outside | |
1979 * the window, even though the thumb does move while the mouse | |
1980 * is outside... This has some funny effects... XXX | |
1981 * So we do special processing when the window de/activates. | |
1982 */ | |
1983 void | |
1984 VimScrollBar::MouseUp(BPoint where) | |
1985 { | |
1986 // BMessage *m = Window()->CurrentMessage(); | |
1987 // m->PrintToStream(); | |
1988 | |
1989 atomic_add(&scrollEventCount, 1); | |
1990 | |
1991 struct VimScrollBarMsg sm; | |
1992 | |
1993 sm.sb = this; | |
1994 sm.value = (long) Value(); | |
1995 sm.stillDragging = FALSE; | |
1996 | |
1997 write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); | |
1998 | |
1999 // calls gui_drag_scrollbar(sb, newValue, FALSE); | |
2000 | |
2001 Inherited::MouseUp(where); | |
2002 } | |
2003 | |
2004 void | |
2005 VimScrollBar::SetValue(float newValue) | |
2006 { | |
2007 if (newValue == Value()) | |
2008 return; | |
2009 | |
2010 ignoreValue = newValue; | |
2011 Inherited::SetValue(newValue); | |
2012 } | |
2013 | |
2014 // ---------------- VimFont ---------------- | |
2015 | |
2016 VimFont::VimFont(): BFont() | |
2017 { | |
2018 init(); | |
2019 } | |
2020 | |
2021 VimFont::VimFont(const VimFont *rhs): BFont(rhs) | |
2022 { | |
2023 init(); | |
2024 } | |
2025 | |
2026 VimFont::VimFont(const BFont *rhs): BFont(rhs) | |
2027 { | |
2028 init(); | |
2029 } | |
2030 | |
2031 VimFont::VimFont(const VimFont &rhs): BFont(rhs) | |
2032 { | |
2033 init(); | |
2034 } | |
2035 | |
2036 VimFont::~VimFont() | |
2037 { | |
2038 } | |
2039 | |
2040 void | |
2041 VimFont::init() | |
2042 { | |
2043 next = NULL; | |
2044 refcount = 1; | |
2045 name = NULL; | |
2046 } | |
2047 | |
2048 // ---------------- VimDialog ---------------- | |
2049 | |
2050 #if defined(FEAT_GUI_DIALOG) | |
2051 | |
2052 const unsigned int kVimDialogButtonMsg = 'VMDB'; | |
2053 const unsigned int kVimDialogIconStripeWidth = 30; | |
2054 const unsigned int kVimDialogButtonsSpacingX = 9; | |
2055 const unsigned int kVimDialogButtonsSpacingY = 4; | |
2056 const unsigned int kVimDialogSpacingX = 6; | |
2057 const unsigned int kVimDialogSpacingY = 10; | |
2058 const unsigned int kVimDialogMinimalWidth = 310; | |
2059 const unsigned int kVimDialogMinimalHeight = 75; | |
2060 const BRect kDefaultRect = | |
2061 BRect(0, 0, kVimDialogMinimalWidth, kVimDialogMinimalHeight); | |
2062 | |
2063 VimDialog::VimDialog(int type, const char *title, const char *message, | |
2064 const char *buttons, int dfltbutton, const char *textfield, int ex_cmd) | |
2065 : BWindow(kDefaultRect, title, B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, | |
2066 B_NOT_CLOSABLE | B_NOT_RESIZABLE | | |
2067 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) | |
2068 , fDialogSem(-1) | |
2069 , fDialogValue(dfltbutton) | |
2070 , fMessageView(NULL) | |
2071 , fInputControl(NULL) | |
2072 , fInputValue(textfield) | |
2073 { | |
2074 // master view | |
2075 VimDialog::View* view = new VimDialog::View(Bounds()); | |
2076 if(view == NULL) | |
2077 return; | |
2078 | |
2079 if(title == NULL) | |
2080 SetTitle("Vim " VIM_VERSION_MEDIUM); | |
2081 | |
2082 AddChild(view); | |
2083 | |
2084 // icon | |
2085 view->InitIcon(type); | |
2086 | |
2087 // buttons | |
2088 int32 which = 1; | |
2089 float maxButtonWidth = 0; | |
2090 float maxButtonHeight = 0; | |
2091 float buttonsWidth = 0; | |
2092 float buttonsHeight = 0; | |
2093 BString strButtons(buttons); | |
2094 strButtons.RemoveAll("&"); | |
2095 do { | |
2096 int32 end = strButtons.FindFirst('\n'); | |
2097 if(end != B_ERROR) | |
2098 strButtons.SetByteAt(end, '\0'); | |
2099 | |
2100 BButton *button = _CreateButton(which++, strButtons.String()); | |
2101 view->AddChild(button); | |
2102 fButtonsList.AddItem(button); | |
2103 | |
2104 maxButtonWidth = max_c(maxButtonWidth, button->Bounds().Width()); | |
2105 maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height()); | |
2106 buttonsWidth += button->Bounds().Width(); | |
2107 buttonsHeight += button->Bounds().Height(); | |
2108 | |
2109 if(end == B_ERROR) | |
2110 break; | |
2111 | |
2112 strButtons.Remove(0, end + 1); | |
2113 } while(true); | |
2114 | |
2115 int32 buttonsCount = fButtonsList.CountItems(); | |
2116 buttonsWidth += kVimDialogButtonsSpacingX * (buttonsCount - 1); | |
2117 buttonsHeight += kVimDialogButtonsSpacingY * (buttonsCount - 1); | |
2118 float dialogWidth = buttonsWidth + kVimDialogIconStripeWidth + | |
2119 kVimDialogSpacingX * 2; | |
2120 float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3; | |
2121 | |
2122 // Check 'v' flag in 'guioptions': vertical button placement. | |
2123 bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) || | |
2124 dialogWidth >= gui.vimWindow->Bounds().Width(); | |
2125 if(vertical) { | |
2126 dialogWidth -= buttonsWidth; | |
2127 dialogWidth += maxButtonWidth; | |
2128 dialogHeight -= maxButtonHeight; | |
2129 dialogHeight += buttonsHeight; | |
2130 } | |
2131 | |
2132 dialogWidth = max_c(dialogWidth, kVimDialogMinimalWidth); | |
2133 | |
2134 // message view | |
2135 BRect rect(0, 0, dialogWidth, 0); | |
2136 rect.left += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX; | |
2137 rect.top += kVimDialogSpacingY; | |
2138 rect.right -= kVimDialogSpacingX; | |
2139 rect.bottom = rect.top; | |
2140 fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN), | |
2141 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); | |
2142 | |
2143 fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); | |
2144 rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); | |
2145 fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); | |
2146 fMessageView->SetText(message); | |
2147 fMessageView->MakeEditable(false); | |
2148 fMessageView->MakeSelectable(false); | |
2149 fMessageView->SetWordWrap(true); | |
2150 AddChild(fMessageView); | |
2151 | |
2152 float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines()); | |
2153 fMessageView->ResizeBy(0, messageHeight); | |
2154 fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight)); | |
2155 | |
2156 dialogHeight += messageHeight; | |
2157 | |
2158 // input view | |
2159 if(fInputValue != NULL) { | |
2160 rect.top = | |
2161 rect.bottom += messageHeight + kVimDialogSpacingY; | |
2162 fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL, | |
2163 B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED); | |
2164 fInputControl->TextView()->SetText(fInputValue); | |
2165 fInputControl->TextView()->SetWordWrap(false); | |
2166 AddChild(fInputControl); | |
2167 | |
2168 float width = 0.f, height = 0.f; | |
2169 fInputControl->GetPreferredSize(&width, &height); | |
2170 fInputControl->MakeFocus(true); | |
2171 | |
2172 dialogHeight += height + kVimDialogSpacingY * 1.5; | |
2173 } | |
2174 | |
2175 dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight); | |
2176 | |
2177 ResizeTo(dialogWidth, dialogHeight); | |
2178 MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2, | |
2179 (gui.vimWindow->Bounds().Height() - dialogHeight) / 2); | |
2180 | |
2181 // adjust layout of buttons | |
2182 float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66); | |
2183 BPoint origin(dialogWidth, dialogHeight); | |
2184 origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth); | |
2185 origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight : maxButtonHeight); | |
2186 | |
2187 for(int32 i = 0 ; i < buttonsCount; i++) { | |
2188 BButton *button = (BButton*)fButtonsList.ItemAt(i); | |
2189 button->MoveTo(origin); | |
2190 if(vertical) { | |
2191 origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY; | |
2192 button->ResizeTo(buttonWidth, button->Frame().Height()); | |
2193 } else | |
2194 origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX; | |
2195 | |
2196 if(dfltbutton == i + 1) { | |
2197 button->MakeDefault(true); | |
2198 button->MakeFocus(fInputControl == NULL); | |
2199 } | |
2200 } | |
2201 } | |
2202 | |
2203 VimDialog::~VimDialog() | |
2204 { | |
2205 if(fDialogSem > B_OK) | |
2206 delete_sem(fDialogSem); | |
2207 } | |
2208 | |
2209 int | |
2210 VimDialog::Go() | |
2211 { | |
2212 fDialogSem = create_sem(0, "VimDialogSem"); | |
2213 if(fDialogSem < B_OK) { | |
2214 Quit(); | |
2215 return fDialogValue; | |
2216 } | |
2217 | |
2218 Show(); | |
2219 | |
2220 while(acquire_sem(fDialogSem) == B_INTERRUPTED); | |
2221 | |
2222 int retValue = fDialogValue; | |
2223 if(fInputValue != NULL) | |
2224 vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1); | |
2225 | |
2226 if(Lock()) | |
2227 Quit(); | |
2228 | |
2229 return retValue; | |
2230 } | |
2231 | |
2232 void VimDialog::MessageReceived(BMessage *msg) | |
2233 { | |
2234 int32 which = 0; | |
2235 if(msg->what != kVimDialogButtonMsg || | |
2236 msg->FindInt32("which", &which) != B_OK) | |
2237 return BWindow::MessageReceived(msg); | |
2238 | |
2239 fDialogValue = which; | |
2240 delete_sem(fDialogSem); | |
2241 fDialogSem = -1; | |
2242 } | |
2243 | |
2244 BButton* VimDialog::_CreateButton(int32 which, const char* label) | |
2245 { | |
2246 BMessage *message = new BMessage(kVimDialogButtonMsg); | |
2247 message->AddInt32("which", which); | |
2248 | |
2249 BRect rect(0, 0, 0, 0); | |
2250 BString name; | |
2251 name << "_b" << which << "_"; | |
2252 | |
2253 BButton* button = new BButton(rect, name.String(), label, message, | |
2254 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); | |
2255 | |
2256 float width = 0.f, height = 0.f; | |
2257 button->GetPreferredSize(&width, &height); | |
2258 button->ResizeTo(width, height); | |
2259 | |
2260 return button; | |
2261 } | |
2262 | |
2263 VimDialog::View::View(BRect frame) | |
2264 : BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), | |
2265 fIconBitmap(NULL) | |
2266 { | |
2267 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); | |
2268 } | |
2269 | |
2270 VimDialog::View::~View() | |
2271 { | |
2272 delete fIconBitmap; | |
2273 } | |
2274 | |
2275 void VimDialog::View::Draw(BRect updateRect) | |
2276 { | |
2277 BRect stripeRect = Bounds(); | |
2278 stripeRect.right = kVimDialogIconStripeWidth; | |
2279 SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); | |
2280 FillRect(stripeRect); | |
2281 | |
2282 if(fIconBitmap == NULL) | |
2283 return; | |
2284 | |
2285 SetDrawingMode(B_OP_ALPHA); | |
2286 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); | |
2287 DrawBitmapAsync(fIconBitmap, BPoint(18, 6)); | |
2288 } | |
2289 | |
2290 void VimDialog::View::InitIcon(int32 type) | |
2291 { | |
2292 if(type == VIM_GENERIC) | |
2293 return; | |
2294 | |
2295 BPath path; | |
2296 status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path); | |
2297 if(status != B_OK) { | |
2298 fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status)); | |
2299 return; | |
2300 } | |
2301 | |
2302 path.Append("app_server"); | |
2303 | |
2304 BFile file(path.Path(), O_RDONLY); | |
2305 if(file.InitCheck() != B_OK) { | |
2306 fprintf(stderr, "App file assignment failed:%s\n", | |
2307 strerror(file.InitCheck())); | |
2308 return; | |
2309 } | |
2310 | |
2311 BResources resources(&file); | |
2312 if(resources.InitCheck() != B_OK) { | |
2313 fprintf(stderr, "App server resources assignment failed:%s\n", | |
2314 strerror(resources.InitCheck())); | |
2315 return; | |
2316 } | |
2317 | |
2318 const char *name = ""; | |
2319 switch(type) { | |
2320 case VIM_ERROR: name = "stop"; break; | |
2321 case VIM_WARNING: name = "warn"; break; | |
2322 case VIM_INFO: name = "info"; break; | |
2323 case VIM_QUESTION: name = "idea"; break; | |
2324 default: return; | |
2325 } | |
2326 | |
2327 int32 iconSize = 32; | |
2328 fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32); | |
2329 if(fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) { | |
2330 fprintf(stderr, "Icon bitmap allocation failed:%s\n", | |
2331 (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck())); | |
2332 return; | |
2333 } | |
2334 | |
2335 size_t size = 0; | |
2336 const uint8* iconData = NULL; | |
2337 // try vector icon first? | |
2338 iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size); | |
2339 if(iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK) | |
2340 return; | |
2341 | |
2342 // try bitmap icon now | |
2343 iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size); | |
2344 if(iconData == NULL) { | |
2345 fprintf(stderr, "Bitmap icon resource not found\n"); | |
2346 delete fIconBitmap; | |
2347 fIconBitmap = NULL; | |
2348 return; | |
2349 } | |
2350 | |
2351 if(fIconBitmap->ColorSpace() != B_CMAP8) | |
2352 BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap); | |
2353 } | |
2354 | |
2355 const unsigned int kVimDialogOKButtonMsg = 'FDOK'; | |
2356 const unsigned int kVimDialogCancelButtonMsg = 'FDCN'; | |
2357 const unsigned int kVimDialogSizeInputMsg = 'SICH'; | |
2358 const unsigned int kVimDialogFamilySelectMsg = 'MSFM'; | |
2359 const unsigned int kVimDialogStyleSelectMsg = 'MSST'; | |
2360 const unsigned int kVimDialogSizeSelectMsg = 'MSSZ'; | |
2361 | |
2362 VimSelectFontDialog::VimSelectFontDialog(font_family* family, font_style* style, float* size) | |
2363 : BWindow(kDefaultRect, "Font Selection", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, | |
2364 B_NOT_CLOSABLE | B_NOT_RESIZABLE | | |
2365 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) | |
2366 , fStatus(B_NO_INIT) | |
2367 , fDialogSem(-1) | |
2368 , fDialogValue(false) | |
2369 , fFamily(family) | |
2370 , fStyle(style) | |
2371 , fSize(size) | |
2372 , fFontSize(*size) | |
2373 , fPreview(0) | |
2374 , fFamiliesList(0) | |
2375 , fStylesList(0) | |
2376 , fSizesList(0) | |
2377 , fSizesInput(0) | |
2378 { | |
2379 strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH); | |
2380 strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH); | |
2381 | |
2382 // "client" area view | |
2383 BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES, | |
2384 B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED, | |
2385 B_PLAIN_BORDER); | |
2386 AddChild(clientBox); | |
2387 | |
2388 // client view | |
2389 BRect RC = clientBox->Bounds(); | |
2390 RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY); | |
2391 BRect rc(RC.LeftTop(), RC.LeftTop()); | |
2392 | |
2393 // at first create all controls | |
2394 fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono"); | |
2395 clientBox->AddChild(fPreview); | |
2396 | |
2397 BBox* boxDivider = new BBox(rc, B_EMPTY_STRING, | |
2398 B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER); | |
2399 clientBox->AddChild(boxDivider); | |
2400 | |
2401 BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:"); | |
2402 clientBox->AddChild(labelFamily); | |
2403 labelFamily->ResizeToPreferred(); | |
2404 | |
2405 BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:"); | |
2406 clientBox->AddChild(labelStyle); | |
2407 labelStyle->ResizeToPreferred(); | |
2408 | |
2409 BStringView *labelSize = new BStringView(rc, "labelSize", "Size:"); | |
2410 clientBox->AddChild(labelSize); | |
2411 labelSize->ResizeToPreferred(); | |
2412 | |
2413 fFamiliesList = new BListView(rc, "listFamily", | |
2414 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); | |
2415 BScrollView *scrollFamilies = new BScrollView("scrollFamily", | |
2416 fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); | |
2417 clientBox->AddChild(scrollFamilies); | |
2418 | |
2419 fStylesList= new BListView(rc, "listStyles", | |
2420 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); | |
2421 BScrollView *scrollStyles = new BScrollView("scrollStyle", | |
2422 fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); | |
2423 clientBox->AddChild(scrollStyles); | |
2424 | |
2425 fSizesInput = new BTextControl(rc, "inputSize", NULL, "???", | |
2426 new BMessage(kVimDialogSizeInputMsg)); | |
2427 clientBox->AddChild(fSizesInput); | |
2428 fSizesInput->ResizeToPreferred(); | |
2429 | |
2430 fSizesList = new BListView(rc, "listSizes", | |
2431 B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); | |
2432 BScrollView *scrollSizes = new BScrollView("scrollSize", | |
2433 fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); | |
2434 clientBox->AddChild(scrollSizes); | |
2435 | |
2436 BButton *buttonOK = new BButton(rc, "buttonOK", "OK", | |
2437 new BMessage(kVimDialogOKButtonMsg)); | |
2438 clientBox->AddChild(buttonOK); | |
2439 buttonOK->ResizeToPreferred(); | |
2440 | |
2441 BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel", | |
2442 new BMessage(kVimDialogCancelButtonMsg)); | |
2443 clientBox->AddChild(buttonCancel); | |
2444 buttonCancel->ResizeToPreferred(); | |
2445 | |
2446 // layout controls | |
2447 float lineHeight = labelFamily->Bounds().Height(); | |
2448 float previewHeight = lineHeight * 3; | |
2449 float offsetYLabels = previewHeight + kVimDialogSpacingY; | |
2450 float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2; | |
2451 float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2; | |
2452 float listsHeight = lineHeight * 9; | |
2453 float offsetYButtons = offsetYLists + listsHeight + kVimDialogSpacingY; | |
2454 float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height(); | |
2455 float familiesWidth = labelFamily->Bounds().Width() * 5; | |
2456 float offsetXStyles = familiesWidth + kVimDialogSpacingX; | |
2457 float stylesWidth = labelStyle->Bounds().Width() * 4; | |
2458 float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX; | |
2459 float sizesWidth = labelSize->Bounds().Width() * 2; | |
2460 float maxControlsWidth = offsetXSizes + sizesWidth; | |
2461 | |
2462 ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2, | |
2463 maxControlsHeight + kVimDialogSpacingY * 2); | |
2464 | |
2465 BRect rcVim = gui.vimWindow->Frame(); | |
2466 MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2, | |
2467 rcVim.top + (rcVim.Height() - Frame().Height()) / 2); | |
2468 | |
2469 fPreview->ResizeTo(maxControlsWidth, previewHeight); | |
2470 fPreview->SetAlignment(B_ALIGN_CENTER); | |
2471 | |
2472 boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2); | |
2473 boxDivider->ResizeTo(maxControlsWidth, 1.f); | |
2474 | |
2475 labelFamily->MoveBy(0.f, offsetYLabels); | |
2476 labelStyle->MoveBy(offsetXStyles, offsetYLabels); | |
2477 labelSize->MoveBy(offsetXSizes, offsetYLabels); | |
2478 | |
2479 // text control alignment issues | |
2480 float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); | |
2481 float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); | |
2482 | |
2483 scrollFamilies->MoveBy(0.f, offsetYLists); | |
2484 scrollStyles->MoveBy(offsetXStyles, offsetYLists); | |
2485 fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2); | |
2486 scrollSizes->MoveBy(offsetXSizes, offsetYSizes); | |
2487 | |
2488 fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER); | |
2489 | |
2490 scrollFamilies->ResizeTo(familiesWidth, listsHeight); | |
2491 scrollStyles->ResizeTo(stylesWidth, listsHeight); | |
2492 fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height()); | |
2493 scrollSizes->ResizeTo(sizesWidth, | |
2494 listsHeight - (offsetYSizes - offsetYLists)); | |
2495 | |
2496 buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons); | |
2497 buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width() | |
2498 - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons); | |
2499 | |
2500 // fill lists | |
2501 int selIndex = -1; | |
2502 int count = count_font_families(); | |
2503 for (int i = 0; i < count; i++) { | |
2504 font_family family; | |
2505 if (get_font_family(i, &family ) == B_OK) { | |
2506 fFamiliesList->AddItem(new BStringItem((const char*)family)); | |
2507 if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0) | |
2508 selIndex = i; | |
2509 } | |
2510 } | |
2511 | |
2512 if (selIndex >= 0) { | |
2513 fFamiliesList->Select(selIndex); | |
2514 fFamiliesList->ScrollToSelection(); | |
2515 } | |
2516 | |
2517 _UpdateFontStyles(); | |
2518 | |
2519 selIndex = -1; | |
2520 for (int size = 8, index = 0; size <= 18; size++, index++) { | |
2521 BString str; | |
2522 str << size; | |
2523 fSizesList->AddItem(new BStringItem(str)); | |
2524 if (size == fFontSize) | |
2525 selIndex = index; | |
2526 | |
2527 } | |
2528 | |
2529 if (selIndex >= 0) { | |
2530 fSizesList->Select(selIndex); | |
2531 fSizesList->ScrollToSelection(); | |
2532 } | |
2533 | |
2534 fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg)); | |
2535 fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg)); | |
2536 fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg)); | |
2537 fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg)); | |
2538 | |
2539 _UpdateSizeInputPreview(); | |
2540 _UpdateFontPreview(); | |
2541 | |
2542 fStatus = B_OK; | |
2543 } | |
2544 | |
2545 VimSelectFontDialog::~VimSelectFontDialog() | |
2546 { | |
2547 _CleanList(fFamiliesList); | |
2548 _CleanList(fStylesList); | |
2549 _CleanList(fSizesList); | |
2550 | |
2551 if (fDialogSem > B_OK) | |
2552 delete_sem(fDialogSem); | |
2553 } | |
2554 | |
2555 void | |
2556 VimSelectFontDialog::_CleanList(BListView* list) | |
2557 { | |
2558 while(0 < list->CountItems()) | |
2559 delete (dynamic_cast<BStringItem*>(list->RemoveItem((int32)0))); | |
2560 } | |
2561 | |
2562 bool | |
2563 VimSelectFontDialog::Go() | |
2564 { | |
2565 if (fStatus != B_OK) { | |
2566 Quit(); | |
2567 return NOFONT; | |
2568 } | |
2569 | |
2570 fDialogSem = create_sem(0, "VimFontSelectDialogSem"); | |
2571 if(fDialogSem < B_OK) { | |
2572 Quit(); | |
2573 return fDialogValue; | |
2574 } | |
2575 | |
2576 Show(); | |
2577 | |
2578 while(acquire_sem(fDialogSem) == B_INTERRUPTED); | |
2579 | |
2580 bool retValue = fDialogValue; | |
2581 | |
2582 if(Lock()) | |
2583 Quit(); | |
2584 | |
2585 return retValue; | |
2586 } | |
2587 | |
2588 | |
2589 void VimSelectFontDialog::_UpdateFontStyles() | |
2590 { | |
2591 _CleanList(fStylesList); | |
2592 | |
2593 int32 selIndex = -1; | |
2594 int32 count = count_font_styles(fFontFamily); | |
2595 for (int32 i = 0; i < count; i++) { | |
2596 font_style style; | |
2597 uint32 flags = 0; | |
2598 if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) { | |
2599 fStylesList->AddItem(new BStringItem((const char*)style)); | |
2600 if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0) | |
2601 selIndex = i; | |
2602 } | |
2603 } | |
2604 | |
2605 if (selIndex >= 0) { | |
2606 fStylesList->Select(selIndex); | |
2607 fStylesList->ScrollToSelection(); | |
2608 } else | |
2609 fStylesList->Select(0); | |
2610 } | |
2611 | |
2612 | |
2613 void VimSelectFontDialog::_UpdateSizeInputPreview() | |
2614 { | |
2615 char buf[10] = {0}; | |
2616 vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize); | |
2617 fSizesInput->SetText(buf); | |
2618 } | |
2619 | |
2620 | |
2621 void VimSelectFontDialog::_UpdateFontPreview() | |
2622 { | |
2623 BFont font; | |
2624 fPreview->GetFont(&font); | |
2625 font.SetSize(fFontSize); | |
2626 font.SetFamilyAndStyle(fFontFamily, fFontStyle); | |
2627 fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE); | |
2628 | |
2629 BString str; | |
2630 str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt."; | |
2631 fPreview->SetText(str); | |
2632 } | |
2633 | |
2634 | |
2635 bool | |
2636 VimSelectFontDialog::_UpdateFromListItem(BListView* list, char* text, int textSize) | |
2637 { | |
2638 int32 index = list->CurrentSelection(); | |
2639 if (index < 0) | |
2640 return false; | |
2641 BStringItem* item = (BStringItem*)list->ItemAt(index); | |
2642 if (item == NULL) | |
2643 return false; | |
2644 strncpy(text, item->Text(), textSize); | |
2645 return true; | |
2646 } | |
2647 | |
2648 | |
2649 void VimSelectFontDialog::MessageReceived(BMessage *msg) | |
2650 { | |
2651 switch (msg->what) { | |
2652 case kVimDialogOKButtonMsg: | |
2653 strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH); | |
2654 strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH); | |
2655 *fSize = fFontSize; | |
2656 fDialogValue = true; | |
2657 case kVimDialogCancelButtonMsg: | |
2658 delete_sem(fDialogSem); | |
2659 fDialogSem = -1; | |
2660 return; | |
2661 case B_KEY_UP: | |
2662 { | |
2663 int32 key = 0; | |
2664 if (msg->FindInt32("raw_char", &key) == B_OK | |
2665 && key == B_ESCAPE) { | |
2666 delete_sem(fDialogSem); | |
2667 fDialogSem = -1; | |
2668 } | |
2669 } | |
2670 break; | |
2671 | |
2672 case kVimDialogFamilySelectMsg: | |
2673 if (_UpdateFromListItem(fFamiliesList, | |
2674 fFontFamily, B_FONT_FAMILY_LENGTH)) { | |
2675 _UpdateFontStyles(); | |
2676 _UpdateFontPreview(); | |
2677 } | |
2678 break; | |
2679 case kVimDialogStyleSelectMsg: | |
2680 if (_UpdateFromListItem(fStylesList, | |
2681 fFontStyle, B_FONT_STYLE_LENGTH)) | |
2682 _UpdateFontPreview(); | |
2683 break; | |
2684 case kVimDialogSizeSelectMsg: | |
2685 { | |
2686 char buf[10] = {0}; | |
2687 if (_UpdateFromListItem(fSizesList, buf, sizeof(buf))) { | |
2688 float size = atof(buf); | |
2689 if (size > 0.f) { | |
2690 fFontSize = size; | |
2691 _UpdateSizeInputPreview(); | |
2692 _UpdateFontPreview(); | |
2693 } | |
2694 } | |
2695 } | |
2696 break; | |
2697 case kVimDialogSizeInputMsg: | |
2698 { | |
2699 float size = atof(fSizesInput->Text()); | |
2700 if (size > 0.f) { | |
2701 fFontSize = size; | |
2702 _UpdateFontPreview(); | |
2703 } | |
2704 } | |
2705 break; | |
2706 default: | |
2707 break; | |
2708 } | |
2709 return BWindow::MessageReceived(msg); | |
2710 } | |
2711 | |
2712 #endif // FEAT_GUI_DIALOG | |
2713 | |
2714 #ifdef FEAT_TOOLBAR | |
2715 | |
2716 // some forward declaration required by toolbar functions... | |
2717 static BMessage * MenuMessage(vimmenu_T *menu); | |
2718 | |
2719 VimToolbar::VimToolbar(BRect frame, const char *name) : | |
2720 BBox(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER) | |
2721 { | |
2722 } | |
2723 | |
2724 VimToolbar::~VimToolbar() | |
2725 { | |
2726 int32 count = fButtonsList.CountItems(); | |
2727 for(int32 i = 0; i < count; i++) | |
2728 delete (BPictureButton*)fButtonsList.ItemAt(i); | |
2729 fButtonsList.MakeEmpty(); | |
2730 | |
2731 delete normalButtonsBitmap; | |
2732 delete grayedButtonsBitmap; | |
2733 normalButtonsBitmap = NULL; | |
2734 grayedButtonsBitmap = NULL; | |
2735 } | |
2736 | |
2737 void | |
2738 VimToolbar::AttachedToWindow() | |
2739 { | |
2740 BBox::AttachedToWindow(); | |
2741 | |
2742 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); | |
2743 } | |
2744 | |
2745 float | |
2746 VimToolbar::ToolbarHeight() const | |
2747 { | |
2748 float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); | |
2749 return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; | |
2750 } | |
2751 | |
2752 bool | |
2753 VimToolbar::ModifyBitmapToGrayed(BBitmap *bitmap) | |
2754 { | |
2755 float height = bitmap->Bounds().Height(); | |
2756 float width = bitmap->Bounds().Width(); | |
2757 | |
2758 rgb_color *bits = (rgb_color*)bitmap->Bits(); | |
2759 int32 pixels = bitmap->BitsLength() / 4; | |
2760 for(int32 i = 0; i < pixels; i++) { | |
2761 bits[i].red = bits[i].green = | |
2762 bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3; | |
2763 bits[i].alpha /= 4; | |
2764 } | |
2765 | |
2766 return true; | |
2767 } | |
2768 | |
2769 bool | |
2770 VimToolbar::PrepareButtonBitmaps() | |
2771 { | |
2772 // first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png | |
2773 normalButtonsBitmap = LoadVimBitmap("builtin-tools.png"); | |
2774 if(normalButtonsBitmap == NULL) | |
2775 // customized not found? dig application resources for "builtin-tools" one | |
2776 normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools"); | |
2777 | |
2778 if(normalButtonsBitmap == NULL) | |
2779 return false; | |
2780 | |
2781 BMessage archive; | |
2782 normalButtonsBitmap->Archive(&archive); | |
2783 | |
2784 grayedButtonsBitmap = new BBitmap(&archive); | |
2785 if(grayedButtonsBitmap == NULL) | |
2786 return false; | |
2787 | |
2788 // modify grayed bitmap | |
2789 ModifyBitmapToGrayed(grayedButtonsBitmap); | |
2790 | |
2791 return true; | |
2792 } | |
2793 | |
2794 BBitmap *VimToolbar::LoadVimBitmap(const char* fileName) | |
2795 { | |
2796 BBitmap *bitmap = NULL; | |
2797 | |
2798 int mustfree = 0; | |
2799 char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree); | |
2800 if(runtimePath != NULL && fileName != NULL) { | |
2801 BString strPath((char*)runtimePath); | |
2802 strPath << "/bitmaps/" << fileName; | |
2803 bitmap = BTranslationUtils::GetBitmap(strPath.String()); | |
2804 } | |
2805 | |
2806 if(mustfree) | |
2807 vim_free(runtimePath); | |
2808 | |
2809 return bitmap; | |
2810 } | |
2811 | |
2812 bool | |
2813 VimToolbar::GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed) | |
2814 { | |
2815 float size = bitmapFrom->Bounds().Height() + 1.; | |
2816 | |
2817 BView view(BRect(0, 0, size, size), "", 0, 0); | |
2818 | |
2819 AddChild(&view); | |
2820 view.BeginPicture(pictureTo); | |
2821 | |
2822 view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); | |
2823 view.FillRect(view.Bounds()); | |
2824 view.SetDrawingMode(B_OP_OVER); | |
2825 | |
2826 BRect source(0, 0, size - 1, size - 1); | |
2827 BRect destination(source); | |
2828 | |
2829 source.OffsetBy(size * index, 0); | |
2830 destination.OffsetBy(ButtonMargin, ButtonMargin); | |
2831 | |
2832 view.DrawBitmap(bitmapFrom, source, destination); | |
2833 | |
2834 if(pressed) { | |
2835 rgb_color shineColor = ui_color(B_SHINE_COLOR); | |
2836 rgb_color shadowColor = ui_color(B_SHADOW_COLOR); | |
2837 size += ButtonMargin * 2 - 1; | |
2838 view.BeginLineArray(4); | |
2839 view.AddLine(BPoint(0, 0), BPoint(size, 0), shadowColor); | |
2840 view.AddLine(BPoint(size, 0), BPoint(size, size), shineColor); | |
2841 view.AddLine(BPoint(size, size), BPoint(0, size), shineColor); | |
2842 view.AddLine(BPoint(0, size), BPoint(0, 0), shadowColor); | |
2843 view.EndLineArray(); | |
2844 } | |
2845 | |
2846 view.EndPicture(); | |
2847 RemoveChild(&view); | |
2848 | |
2849 return true; | |
2850 } | |
2851 | |
2852 bool | |
2853 VimToolbar::AddButton(int32 index, vimmenu_T *menu) | |
2854 { | |
2855 BPictureButton *button = NULL; | |
2856 if(!menu_is_separator(menu->name)) { | |
2857 float size = normalButtonsBitmap ? | |
2858 normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.; | |
2859 BRect frame(0, 0, size, size); | |
2860 BPicture pictureOn; | |
2861 BPicture pictureOff; | |
2862 BPicture pictureGray; | |
2863 | |
2864 if(menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) { | |
2865 GetPictureFromBitmap(&pictureOn, menu->iconidx, normalButtonsBitmap, true); | |
2866 GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false); | |
2867 GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false); | |
2868 } else { | |
2869 | |
2870 char_u buffer[MAXPATHL] = {0}; | |
2871 BBitmap *bitmap = NULL; | |
2872 | |
2873 if(menu->iconfile) { | |
2874 gui_find_iconfile(menu->iconfile, buffer, (char*)"png"); | |
2875 bitmap = BTranslationUtils::GetBitmap((char*)buffer); | |
2876 } | |
2877 | |
2878 if(bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK) | |
2879 bitmap = BTranslationUtils::GetBitmap((char*)buffer); | |
2880 | |
2881 if(bitmap == NULL) | |
2882 bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32); | |
2883 | |
2884 GetPictureFromBitmap(&pictureOn, 0, bitmap, true); | |
2885 GetPictureFromBitmap(&pictureOff, 0, bitmap, false); | |
2886 ModifyBitmapToGrayed(bitmap); | |
2887 GetPictureFromBitmap(&pictureGray, 0, bitmap, false); | |
2888 | |
2889 delete bitmap; | |
2890 } | |
2891 | |
2892 button = new BPictureButton(frame, (char*)menu->name, | |
2893 &pictureOff, &pictureOn, MenuMessage(menu)); | |
2894 | |
2895 button->SetDisabledOn(&pictureGray); | |
2896 button->SetDisabledOff(&pictureGray); | |
2897 | |
2898 button->SetTarget(gui.vimTextArea); | |
2899 | |
2900 AddChild(button); | |
2901 | |
2902 menu->button = button; | |
2903 } | |
2904 | |
2905 bool result = fButtonsList.AddItem(button, index); | |
2906 InvalidateLayout(); | |
2907 return result; | |
2908 } | |
2909 | |
2910 bool | |
2911 VimToolbar::RemoveButton(vimmenu_T *menu) | |
2912 { | |
2913 if(menu->button) { | |
2914 if(fButtonsList.RemoveItem(menu->button)) { | |
2915 delete menu->button; | |
2916 menu->button = NULL; | |
2917 } | |
2918 } | |
20134
352701a626ed
patch 8.2.0622: Haiku: GUI does not compile
Bram Moolenaar <Bram@vim.org>
parents:
19526
diff
changeset
|
2919 return true; |
19526 | 2920 } |
2921 | |
2922 bool | |
2923 VimToolbar::GrayButton(vimmenu_T *menu, int grey) | |
2924 { | |
2925 if(menu->button) { | |
2926 int32 index = fButtonsList.IndexOf(menu->button); | |
2927 if(index >= 0) | |
2928 menu->button->SetEnabled(grey ? false : true); | |
2929 } | |
20134
352701a626ed
patch 8.2.0622: Haiku: GUI does not compile
Bram Moolenaar <Bram@vim.org>
parents:
19526
diff
changeset
|
2930 return true; |
19526 | 2931 } |
2932 | |
2933 void | |
2934 VimToolbar::InvalidateLayout() | |
2935 { | |
2936 int32 offset = ToolbarMargin; | |
2937 int32 count = fButtonsList.CountItems(); | |
2938 for(int32 i = 0; i < count; i++) { | |
2939 BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i); | |
2940 if(button) { | |
2941 button->MoveTo(offset, ToolbarMargin); | |
2942 offset += button->Bounds().Width() + ToolbarMargin; | |
2943 } else | |
2944 offset += ToolbarMargin * 3; | |
2945 } | |
2946 } | |
2947 | |
2948 #endif /*FEAT_TOOLBAR*/ | |
2949 | |
2950 #if defined(FEAT_GUI_TABLINE) | |
2951 | |
2952 float | |
2953 VimTabLine::TablineHeight() const | |
2954 { | |
2955 // float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); | |
2956 // return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; | |
2957 return TabHeight(); // + ToolbarMargin; | |
2958 } | |
2959 | |
2960 void | |
2961 VimTabLine::MouseDown(BPoint point) | |
2962 { | |
2963 if(!gui_mch_showing_tabline()) | |
2964 return; | |
2965 | |
2966 BMessage *m = Window()->CurrentMessage(); | |
2967 assert(m); | |
2968 | |
2969 int32 buttons = 0; | |
2970 m->FindInt32("buttons", &buttons); | |
2971 | |
2972 int32 clicks = 0; | |
2973 m->FindInt32("clicks", &clicks); | |
2974 | |
2975 int index = 0; // 0 means here - no tab found | |
2976 for (int i = 0; i < CountTabs(); i++) { | |
2977 if(TabFrame(i).Contains(point)) { | |
2978 index = i + 1; // indexes are 1-based | |
2979 break; | |
2980 } | |
2981 } | |
2982 | |
2983 int event = -1; | |
2984 | |
2985 if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1) | |
2986 // left button double click on - create new tab | |
2987 event = TABLINE_MENU_NEW; | |
2988 | |
2989 else if (buttons & B_TERTIARY_MOUSE_BUTTON) | |
2990 // middle button click - close the pointed tab | |
2991 // or create new one in case empty space | |
2992 event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW; | |
2993 | |
2994 else if (buttons & B_SECONDARY_MOUSE_BUTTON) { | |
2995 // right button click - show context menu | |
2996 BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false); | |
2997 popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE))); | |
2998 popUpMenu->AddItem(new BMenuItem(_("New tab T"), new BMessage(TABLINE_MENU_NEW))); | |
2999 popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN))); | |
3000 | |
3001 ConvertToScreen(&point); | |
3002 BMenuItem* item = popUpMenu->Go(point); | |
3003 if (item != NULL) { | |
3004 event = item->Command(); | |
3005 } | |
3006 | |
3007 delete popUpMenu; | |
3008 | |
3009 } else { | |
3010 // default processing | |
3011 BTabView::MouseDown(point); | |
3012 return; | |
3013 } | |
3014 | |
3015 if (event < 0) | |
3016 return; | |
3017 | |
3018 VimTablineMenuMsg tmm; | |
3019 tmm.index = index; | |
3020 tmm.event = event; | |
3021 write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm)); | |
3022 } | |
3023 | |
3024 void | |
3025 VimTabLine::VimTab::Select(BView* owner) | |
3026 { | |
3027 BTab::Select(owner); | |
3028 | |
3029 VimTabLine *tabLine = gui.vimForm->TabLine(); | |
3030 if(tabLine != NULL) { | |
3031 | |
3032 int32 i = 0; | |
3033 for (; i < tabLine->CountTabs(); i++) | |
3034 if(this == tabLine->TabAt(i)) | |
3035 break; | |
3036 | |
3037 // printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label()); | |
3038 if(i < tabLine->CountTabs()) { | |
3039 VimTablineMsg tm; | |
3040 tm.index = i + 1; | |
3041 write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm)); | |
3042 } | |
3043 } | |
3044 } | |
3045 | |
3046 #endif // defined(FEAT_GUI_TABLINE) | |
3047 | |
3048 // ---------------- ---------------- | |
3049 | |
3050 // some global variables | |
3051 static char appsig[] = "application/x-vnd.Haiku-Vim-8"; | |
3052 key_map *keyMap; | |
3053 char *keyMapChars; | |
3054 int main_exitcode = 127; | |
3055 | |
3056 status_t | |
3057 gui_haiku_process_event(bigtime_t timeout) | |
3058 { | |
3059 struct VimMsg vm; | |
3060 int32 what; | |
3061 ssize_t size; | |
3062 | |
3063 size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm), | |
3064 B_TIMEOUT, timeout); | |
3065 | |
3066 if (size >= 0) { | |
3067 switch (what) { | |
3068 case VimMsg::Key: | |
3069 { | |
3070 char_u *string = vm.u.Key.chars; | |
3071 int len = vm.u.Key.length; | |
3072 if (len == 1 && string[0] == Ctrl_chr('C')) { | |
3073 trash_input_buf(); | |
3074 got_int = TRUE; | |
3075 } | |
3076 | |
3077 if (vm.u.Key.csi_escape) | |
3078 #ifndef FEAT_MBYTE_IME | |
3079 { | |
3080 int i; | |
3081 char_u buf[2]; | |
3082 | |
3083 for (i = 0; i < len; ++i) | |
3084 { | |
3085 add_to_input_buf(string + i, 1); | |
3086 if (string[i] == CSI) | |
3087 { | |
3088 // Turn CSI into K_CSI. | |
3089 buf[0] = KS_EXTRA; | |
3090 buf[1] = (int)KE_CSI; | |
3091 add_to_input_buf(buf, 2); | |
3092 } | |
3093 } | |
3094 } | |
3095 #else | |
3096 add_to_input_buf_csi(string, len); | |
3097 #endif | |
3098 else | |
3099 add_to_input_buf(string, len); | |
3100 } | |
3101 break; | |
3102 case VimMsg::Resize: | |
3103 gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height); | |
3104 break; | |
3105 case VimMsg::ScrollBar: | |
3106 { | |
3107 /* | |
3108 * If loads of scroll messages queue up, use only the last | |
3109 * one. Always report when the scrollbar stops dragging. | |
3110 * This is not perfect yet anyway: these events are queued | |
3111 * yet again, this time in the keyboard input buffer. | |
3112 */ | |
3113 int32 oldCount = | |
3114 atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1); | |
3115 if (oldCount <= 1 || !vm.u.Scroll.stillDragging) | |
3116 gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(), | |
3117 vm.u.Scroll.value, vm.u.Scroll.stillDragging); | |
3118 } | |
3119 break; | |
3120 #if defined(FEAT_MENU) | |
3121 case VimMsg::Menu: | |
3122 gui_menu_cb(vm.u.Menu.guiMenu); | |
3123 break; | |
3124 #endif | |
3125 case VimMsg::Mouse: | |
3126 { | |
3127 int32 oldCount; | |
3128 if (vm.u.Mouse.button == MOUSE_DRAG) | |
3129 oldCount = | |
3130 atomic_add(&gui.vimTextArea->mouseDragEventCount, -1); | |
3131 else | |
3132 oldCount = 0; | |
3133 if (oldCount <= 1) | |
3134 gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x, | |
3135 vm.u.Mouse.y, vm.u.Mouse.repeated_click, | |
3136 vm.u.Mouse.modifiers); | |
3137 } | |
3138 break; | |
3139 case VimMsg::MouseMoved: | |
3140 { | |
3141 gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y); | |
3142 } | |
3143 break; | |
3144 case VimMsg::Focus: | |
3145 gui.in_focus = vm.u.Focus.active; | |
3146 // XXX Signal that scrollbar dragging has stopped? | |
3147 // This is needed because we don't get a MouseUp if | |
3148 // that happens while outside the window... :-( | |
3149 if (gui.dragged_sb) { | |
3150 gui.dragged_sb = SBAR_NONE; | |
3151 } | |
3152 // gui_update_cursor(TRUE, FALSE); | |
3153 break; | |
3154 case VimMsg::Refs: | |
3155 ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir); | |
3156 break; | |
3157 case VimMsg::Tabline: | |
3158 send_tabline_event(vm.u.Tabline.index); | |
3159 break; | |
3160 case VimMsg::TablineMenu: | |
3161 send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event); | |
3162 break; | |
3163 default: | |
3164 // unrecognised message, ignore it | |
3165 break; | |
3166 } | |
3167 } | |
3168 | |
3169 /* | |
3170 * If size < B_OK, it is an error code. | |
3171 */ | |
3172 return size; | |
3173 } | |
3174 | |
3175 /* | |
3176 * Here are some functions to protect access to ScreenLines[] and | |
3177 * LineOffset[]. These are used from the window thread to respond | |
3178 * to a Draw() callback. When that occurs, the window is already | |
3179 * locked by the system. | |
3180 * | |
3181 * Other code that needs to lock is any code that changes these | |
3182 * variables. Other read-only access, or access merely to the | |
3183 * contents of the screen buffer, need not be locked. | |
3184 * | |
3185 * If there is no window, don't call Lock() but do succeed. | |
3186 */ | |
3187 | |
3188 int | |
3189 vim_lock_screen() | |
3190 { | |
3191 return !gui.vimWindow || gui.vimWindow->Lock(); | |
3192 } | |
3193 | |
3194 void | |
3195 vim_unlock_screen() | |
3196 { | |
3197 if (gui.vimWindow) | |
3198 gui.vimWindow->Unlock(); | |
3199 } | |
3200 | |
3201 #define RUN_BAPPLICATION_IN_NEW_THREAD 0 | |
3202 | |
3203 #if RUN_BAPPLICATION_IN_NEW_THREAD | |
3204 | |
3205 int32 | |
3206 run_vimapp(void *args) | |
3207 { | |
3208 VimApp app(appsig); | |
3209 | |
3210 gui.vimApp = &app; | |
3211 app.Run(); // Run until Quit() called | |
3212 | |
3213 return 0; | |
3214 } | |
3215 | |
3216 #else | |
3217 | |
3218 int32 | |
3219 call_main(void *args) | |
3220 { | |
3221 struct MainArgs *ma = (MainArgs *)args; | |
3222 | |
3223 return main(ma->argc, ma->argv); | |
3224 } | |
3225 #endif | |
3226 | |
3227 /* | |
3228 * Parse the GUI related command-line arguments. Any arguments used are | |
3229 * deleted from argv, and *argc is decremented accordingly. This is called | |
3230 * when vim is started, whether or not the GUI has been started. | |
3231 */ | |
3232 void | |
3233 gui_mch_prepare( | |
3234 int *argc, | |
3235 char **argv) | |
3236 { | |
3237 /* | |
3238 * We don't have any command line arguments for the BeOS GUI yet, | |
3239 * but this is an excellent place to create our Application object. | |
3240 */ | |
3241 if (!gui.vimApp) { | |
3242 thread_info tinfo; | |
3243 get_thread_info(find_thread(NULL), &tinfo); | |
3244 | |
3245 // May need the port very early on to process RefsReceived() | |
3246 gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP"); | |
3247 | |
3248 #if RUN_BAPPLICATION_IN_NEW_THREAD | |
3249 thread_id tid = spawn_thread(run_vimapp, "vim VimApp", | |
3250 tinfo.priority, NULL); | |
3251 if (tid >= B_OK) { | |
3252 resume_thread(tid); | |
3253 } else { | |
3254 getout(1); | |
3255 } | |
3256 #else | |
3257 MainArgs ma = { *argc, argv }; | |
3258 thread_id tid = spawn_thread(call_main, "vim main()", | |
3259 tinfo.priority, &ma); | |
3260 if (tid >= B_OK) { | |
3261 VimApp app(appsig); | |
3262 | |
3263 gui.vimApp = &app; | |
3264 resume_thread(tid); | |
3265 /* | |
3266 * This is rather horrible. | |
3267 * call_main will call main() again... | |
3268 * There will be no infinite recursion since | |
3269 * gui.vimApp is set now. | |
3270 */ | |
3271 app.Run(); // Run until Quit() called | |
3272 // fprintf(stderr, "app.Run() returned...\n"); | |
3273 status_t dummy_exitcode; | |
3274 (void)wait_for_thread(tid, &dummy_exitcode); | |
3275 | |
3276 /* | |
3277 * This path should be the normal one taken to exit Vim. | |
3278 * The main() thread calls mch_exit() which calls | |
3279 * gui_mch_exit() which terminates its thread. | |
3280 */ | |
3281 exit(main_exitcode); | |
3282 } | |
3283 #endif | |
3284 } | |
3285 // Don't fork() when starting the GUI. Spawned threads are not | |
3286 // duplicated with a fork(). The result is a mess. | |
3287 gui.dofork = FALSE; | |
3288 /* | |
3289 * XXX Try to determine whether we were started from | |
3290 * the Tracker or the terminal. | |
3291 * It would be nice to have this work, because the Tracker | |
3292 * follows symlinks, so even if you double-click on gvim, | |
3293 * when it is a link to vim it will still pass a command name | |
3294 * of vim... | |
3295 * We try here to see if stdin comes from /dev/null. If so, | |
3296 * (or if there is an error, which should never happen) start the GUI. | |
3297 * This does the wrong thing for vim - </dev/null, and we're | |
3298 * too early to see the command line parsing. Tough. | |
3299 * On the other hand, it starts the gui for vim file & which is nice. | |
3300 */ | |
3301 if (!isatty(0)) { | |
3302 struct stat stat_stdin, stat_dev_null; | |
3303 | |
3304 if (fstat(0, &stat_stdin) == -1 || | |
3305 stat("/dev/null", &stat_dev_null) == -1 || | |
3306 (stat_stdin.st_dev == stat_dev_null.st_dev && | |
3307 stat_stdin.st_ino == stat_dev_null.st_ino)) | |
3308 gui.starting = TRUE; | |
3309 } | |
3310 } | |
3311 | |
3312 /* | |
3313 * Check if the GUI can be started. Called before gvimrc is sourced. | |
3314 * Return OK or FAIL. | |
3315 */ | |
3316 int | |
3317 gui_mch_init_check(void) | |
3318 { | |
3319 return OK; // TODO: GUI can always be started? | |
3320 } | |
3321 | |
3322 /* | |
3323 * Initialise the GUI. Create all the windows, set up all the call-backs | |
3324 * etc. | |
3325 */ | |
3326 int | |
3327 gui_mch_init() | |
3328 { | |
3329 display_errors(); | |
3330 gui.def_norm_pixel = RGB(0x00, 0x00, 0x00); // black | |
3331 gui.def_back_pixel = RGB(0xFF, 0xFF, 0xFF); // white | |
3332 gui.norm_pixel = gui.def_norm_pixel; | |
3333 gui.back_pixel = gui.def_back_pixel; | |
3334 | |
3335 gui.scrollbar_width = (int) B_V_SCROLL_BAR_WIDTH; | |
3336 gui.scrollbar_height = (int) B_H_SCROLL_BAR_HEIGHT; | |
3337 #ifdef FEAT_MENU | |
3338 gui.menu_height = 19; // initial guess - | |
3339 // correct for my default settings | |
3340 #endif | |
3341 gui.border_offset = 3; // coordinates are inside window borders | |
3342 | |
3343 if (gui.vdcmp < B_OK) | |
3344 return FAIL; | |
3345 get_key_map(&keyMap, &keyMapChars); | |
3346 | |
3347 gui.vimWindow = new VimWindow(); // hidden and locked | |
3348 if (!gui.vimWindow) | |
3349 return FAIL; | |
3350 | |
3351 gui.vimWindow->Run(); // Run() unlocks but does not show | |
3352 | |
3353 // Get the colors from the "Normal" group (set in syntax.c or in a vimrc | |
3354 // file) | |
3355 set_normal_colors(); | |
3356 | |
3357 /* | |
3358 * Check that none of the colors are the same as the background color | |
3359 */ | |
3360 gui_check_colors(); | |
3361 | |
3362 // Get the colors for the highlight groups (gui_check_colors() might have | |
3363 // changed them) | |
3364 highlight_gui_started(); // re-init colors and fonts | |
3365 | |
3366 gui_mch_new_colors(); // window must exist for this | |
3367 | |
3368 return OK; | |
3369 } | |
3370 | |
3371 /* | |
3372 * Called when the foreground or background color has been changed. | |
3373 */ | |
3374 void | |
3375 gui_mch_new_colors() | |
3376 { | |
3377 rgb_color rgb = GUI_TO_RGB(gui.back_pixel); | |
3378 | |
3379 if (gui.vimWindow->Lock()) { | |
3380 gui.vimForm->SetViewColor(rgb); | |
3381 // Does this not have too much effect for those small rectangles? | |
3382 gui.vimForm->Invalidate(); | |
3383 gui.vimWindow->Unlock(); | |
3384 } | |
3385 } | |
3386 | |
3387 /* | |
3388 * Open the GUI window which was created by a call to gui_mch_init(). | |
3389 */ | |
3390 int | |
3391 gui_mch_open() | |
3392 { | |
3393 if (gui_win_x != -1 && gui_win_y != -1) | |
3394 gui_mch_set_winpos(gui_win_x, gui_win_y); | |
3395 | |
3396 // Actually open the window | |
3397 if (gui.vimWindow->Lock()) { | |
3398 gui.vimWindow->Show(); | |
3399 gui.vimWindow->Unlock(); | |
3400 return OK; | |
3401 } | |
3402 | |
3403 return FAIL; | |
3404 } | |
3405 | |
3406 void | |
3407 gui_mch_exit(int vim_exitcode) | |
3408 { | |
3409 if (gui.vimWindow) { | |
3410 thread_id tid = gui.vimWindow->Thread(); | |
3411 gui.vimWindow->Lock(); | |
3412 gui.vimWindow->Quit(); | |
3413 // Wait until it is truely gone | |
3414 int32 exitcode; | |
3415 wait_for_thread(tid, &exitcode); | |
3416 } | |
3417 delete_port(gui.vdcmp); | |
3418 #if !RUN_BAPPLICATION_IN_NEW_THREAD | |
3419 /* | |
3420 * We are in the main() thread - quit the App thread and | |
3421 * quit ourselves (passing on the exitcode). Use a global since the | |
3422 * value from exit_thread() is only used if wait_for_thread() is | |
3423 * called in time (race condition). | |
3424 */ | |
3425 #endif | |
3426 if (gui.vimApp) { | |
3427 VimTextAreaView::guiBlankMouse(false); | |
3428 | |
3429 main_exitcode = vim_exitcode; | |
3430 #if RUN_BAPPLICATION_IN_NEW_THREAD | |
3431 thread_id tid = gui.vimApp->Thread(); | |
3432 int32 exitcode; | |
3433 gui.vimApp->Lock(); | |
3434 gui.vimApp->Quit(); | |
3435 gui.vimApp->Unlock(); | |
3436 wait_for_thread(tid, &exitcode); | |
3437 #else | |
3438 gui.vimApp->Lock(); | |
3439 gui.vimApp->Quit(); | |
3440 gui.vimApp->Unlock(); | |
3441 // suicide | |
3442 exit_thread(vim_exitcode); | |
3443 #endif | |
3444 } | |
3445 // If we are somehow still here, let mch_exit() handle things. | |
3446 } | |
3447 | |
3448 /* | |
3449 * Get the position of the top left corner of the window. | |
3450 */ | |
3451 int | |
3452 gui_mch_get_winpos(int *x, int *y) | |
3453 { | |
3454 if (gui.vimWindow->Lock()) { | |
3455 BRect r; | |
3456 r = gui.vimWindow->Frame(); | |
3457 gui.vimWindow->Unlock(); | |
3458 *x = (int)r.left; | |
3459 *y = (int)r.top; | |
3460 return OK; | |
3461 } | |
3462 else | |
3463 return FAIL; | |
3464 } | |
3465 | |
3466 /* | |
3467 * Set the position of the top left corner of the window to the given | |
3468 * coordinates. | |
3469 */ | |
3470 void | |
3471 gui_mch_set_winpos(int x, int y) | |
3472 { | |
3473 if (gui.vimWindow->Lock()) { | |
3474 gui.vimWindow->MoveTo(x, y); | |
3475 gui.vimWindow->Unlock(); | |
3476 } | |
3477 } | |
3478 | |
3479 /* | |
3480 * Set the size of the window to the given width and height in pixels. | |
3481 */ | |
3482 void | |
3483 gui_mch_set_shellsize( | |
3484 int width, | |
3485 int height, | |
3486 int min_width, | |
3487 int min_height, | |
3488 int base_width, | |
3489 int base_height, | |
3490 int direction) // TODO: utilize? | |
3491 { | |
3492 /* | |
3493 * We are basically given the size of the VimForm, if I understand | |
3494 * correctly. Since it fills the window completely, this will also | |
3495 * be the size of the window. | |
3496 */ | |
3497 if (gui.vimWindow->Lock()) { | |
3498 gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH); | |
3499 | |
3500 // set size limits | |
3501 float minWidth, maxWidth, minHeight, maxHeight; | |
3502 | |
3503 gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth, | |
3504 &minHeight, &maxHeight); | |
3505 gui.vimWindow->SetSizeLimits(min_width, maxWidth, | |
3506 min_height, maxHeight); | |
3507 | |
3508 /* | |
3509 * Set the resizing alignment depending on font size. | |
3510 */ | |
3511 gui.vimWindow->SetWindowAlignment( | |
3512 B_PIXEL_ALIGNMENT, // window_alignment mode, | |
3513 1, // int32 h, | |
3514 0, // int32 hOffset = 0, | |
3515 gui.char_width, // int32 width = 0, | |
3516 base_width, // int32 widthOffset = 0, | |
3517 1, // int32 v = 0, | |
3518 0, // int32 vOffset = 0, | |
3519 gui.char_height, // int32 height = 0, | |
3520 base_height // int32 heightOffset = 0 | |
3521 ); | |
3522 | |
3523 gui.vimWindow->Unlock(); | |
3524 } | |
3525 } | |
3526 | |
3527 void | |
3528 gui_mch_get_screen_dimensions( | |
3529 int *screen_w, | |
3530 int *screen_h) | |
3531 { | |
3532 BRect frame; | |
3533 | |
3534 { | |
3535 BScreen screen(gui.vimWindow); | |
3536 | |
3537 if (screen.IsValid()) { | |
3538 frame = screen.Frame(); | |
3539 } else { | |
3540 frame.right = 640; | |
3541 frame.bottom = 480; | |
3542 } | |
3543 } | |
3544 | |
3545 // XXX approximations... | |
3546 *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20; | |
3547 *screen_h = (int) frame.bottom - gui.scrollbar_height | |
3548 #ifdef FEAT_MENU | |
3549 - gui.menu_height | |
3550 #endif | |
3551 - 30; | |
3552 } | |
3553 | |
3554 void | |
3555 gui_mch_set_text_area_pos( | |
3556 int x, | |
3557 int y, | |
3558 int w, | |
3559 int h) | |
3560 { | |
3561 if (!gui.vimTextArea) | |
3562 return; | |
3563 | |
3564 if (gui.vimWindow->Lock()) { | |
3565 gui.vimTextArea->MoveTo(x, y); | |
3566 gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); | |
3567 | |
20134
352701a626ed
patch 8.2.0622: Haiku: GUI does not compile
Bram Moolenaar <Bram@vim.org>
parents:
19526
diff
changeset
|
3568 #ifdef FEAT_GUI_TABLINE |
19526 | 3569 if(gui.vimForm->TabLine() != NULL) { |
3570 gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight()); | |
3571 } | |
3572 #endif // FEAT_GUI_TABLINE | |
3573 | |
3574 gui.vimWindow->Unlock(); | |
3575 } | |
3576 } | |
3577 | |
3578 | |
3579 /* | |
3580 * Scrollbar stuff: | |
3581 */ | |
3582 | |
3583 void | |
3584 gui_mch_enable_scrollbar( | |
3585 scrollbar_T *sb, | |
3586 int flag) | |
3587 { | |
3588 VimScrollBar *vsb = sb->id; | |
3589 if (gui.vimWindow->Lock()) { | |
3590 /* | |
3591 * This function is supposed to be idempotent, but Show()/Hide() | |
3592 * is not. Therefore we test if they are needed. | |
3593 */ | |
3594 if (flag) { | |
3595 if (vsb->IsHidden()) { | |
3596 vsb->Show(); | |
3597 } | |
3598 } else { | |
3599 if (!vsb->IsHidden()) { | |
3600 vsb->Hide(); | |
3601 } | |
3602 } | |
3603 gui.vimWindow->Unlock(); | |
3604 } | |
3605 } | |
3606 | |
3607 void | |
3608 gui_mch_set_scrollbar_thumb( | |
3609 scrollbar_T *sb, | |
3610 int val, | |
3611 int size, | |
3612 int max) | |
3613 { | |
3614 if (gui.vimWindow->Lock()) { | |
3615 VimScrollBar *s = sb->id; | |
3616 if (max == 0) { | |
3617 s->SetValue(0); | |
3618 s->SetRange(0.0, 0.0); | |
3619 } else { | |
3620 s->SetProportion((float)size / (max + 1.0)); | |
3621 s->SetSteps(1.0, size > 5 ? size - 2 : size); | |
3622 #ifndef SCROLL_PAST_END // really only defined in gui.c... | |
3623 max = max + 1 - size; | |
3624 #endif | |
3625 if (max < s->Value()) { | |
3626 /* | |
3627 * If the new maximum is lower than the current value, | |
3628 * setting it would cause the value to be clipped and | |
3629 * therefore a ValueChanged() call. | |
3630 * We avoid this by setting the value first, because | |
3631 * it presumably is <= max. | |
3632 */ | |
3633 s->SetValue(val); | |
3634 s->SetRange(0.0, max); | |
3635 } else { | |
3636 /* | |
3637 * In the other case, set the range first, since the | |
3638 * new value might be higher than the current max. | |
3639 */ | |
3640 s->SetRange(0.0, max); | |
3641 s->SetValue(val); | |
3642 } | |
3643 } | |
3644 gui.vimWindow->Unlock(); | |
3645 } | |
3646 } | |
3647 | |
3648 void | |
3649 gui_mch_set_scrollbar_pos( | |
3650 scrollbar_T *sb, | |
3651 int x, | |
3652 int y, | |
3653 int w, | |
3654 int h) | |
3655 { | |
3656 if (gui.vimWindow->Lock()) { | |
3657 BRect winb = gui.vimWindow->Bounds(); | |
3658 float vsbx = x, vsby = y; | |
3659 VimScrollBar *vsb = sb->id; | |
3660 vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); | |
3661 if(winb.right-(x+w)<w) vsbx = winb.right - (w - PEN_WIDTH); | |
3662 vsb->MoveTo(vsbx, vsby); | |
3663 gui.vimWindow->Unlock(); | |
3664 } | |
3665 } | |
3666 | |
3667 void | |
3668 gui_mch_create_scrollbar( | |
3669 scrollbar_T *sb, | |
3670 int orient) // SBAR_VERT or SBAR_HORIZ | |
3671 { | |
3672 orientation posture = | |
3673 (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL; | |
3674 | |
3675 VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture); | |
3676 if (gui.vimWindow->Lock()) { | |
3677 vsb->SetTarget(gui.vimTextArea); | |
3678 vsb->Hide(); | |
3679 gui.vimForm->AddChild(vsb); | |
3680 gui.vimWindow->Unlock(); | |
3681 } | |
3682 } | |
3683 | |
20134
352701a626ed
patch 8.2.0622: Haiku: GUI does not compile
Bram Moolenaar <Bram@vim.org>
parents:
19526
diff
changeset
|
3684 #if defined(FEAT_WINDOWS) || defined(FEAT_GUI_HAIKU) || defined(PROTO) |
19526 | 3685 void |
3686 gui_mch_destroy_scrollbar( | |
3687 scrollbar_T *sb) | |
3688 { | |
3689 if (gui.vimWindow->Lock()) { | |
3690 sb->id->RemoveSelf(); | |
3691 delete sb->id; | |
3692 gui.vimWindow->Unlock(); | |
3693 } | |
3694 } | |
3695 #endif | |
3696 | |
3697 /* | |
3698 * Cursor does not flash | |
3699 */ | |
3700 int | |
3701 gui_mch_is_blink_off(void) | |
3702 { | |
3703 return FALSE; | |
3704 } | |
3705 | |
3706 /* | |
3707 * Cursor blink functions. | |
3708 * | |
3709 * This is a simple state machine: | |
3710 * BLINK_NONE not blinking at all | |
3711 * BLINK_OFF blinking, cursor is not shown | |
3712 * BLINK_ON blinking, cursor is shown | |
3713 */ | |
3714 | |
3715 #define BLINK_NONE 0 | |
3716 #define BLINK_OFF 1 | |
3717 #define BLINK_ON 2 | |
3718 | |
3719 static int blink_state = BLINK_NONE; | |
3720 static long_u blink_waittime = 700; | |
3721 static long_u blink_ontime = 400; | |
3722 static long_u blink_offtime = 250; | |
3723 static int blink_timer = 0; | |
3724 | |
3725 void | |
3726 gui_mch_set_blinking( | |
3727 long waittime, | |
3728 long on, | |
3729 long off) | |
3730 { | |
3731 // TODO | |
3732 blink_waittime = waittime; | |
3733 blink_ontime = on; | |
3734 blink_offtime = off; | |
3735 } | |
3736 | |
3737 /* | |
3738 * Stop the cursor blinking. Show the cursor if it wasn't shown. | |
3739 */ | |
3740 void | |
20134
352701a626ed
patch 8.2.0622: Haiku: GUI does not compile
Bram Moolenaar <Bram@vim.org>
parents:
19526
diff
changeset
|
3741 gui_mch_stop_blink(int may_call_gui_update_cursor) |
19526 | 3742 { |
3743 // TODO | |
3744 if (blink_timer != 0) | |
3745 { | |
3746 // XtRemoveTimeOut(blink_timer); | |
3747 blink_timer = 0; | |
3748 } | |
3749 if (blink_state == BLINK_OFF) | |
3750 gui_update_cursor(TRUE, FALSE); | |
3751 blink_state = BLINK_NONE; | |
3752 } | |
3753 | |
3754 /* | |
3755 * Start the cursor blinking. If it was already blinking, this restarts the | |
3756 * waiting time and shows the cursor. | |
3757 */ | |
3758 void | |
3759 gui_mch_start_blink() | |
3760 { | |
3761 // TODO | |
3762 if (blink_timer != 0) | |
3763 ;// XtRemoveTimeOut(blink_timer); | |
3764 // Only switch blinking on if none of the times is zero | |
3765 if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) | |
3766 { | |
3767 blink_timer = 1; // XtAppAddTimeOut(app_context, blink_waittime, | |
3768 blink_state = BLINK_ON; | |
3769 gui_update_cursor(TRUE, FALSE); | |
3770 } | |
3771 } | |
3772 | |
3773 /* | |
3774 * Initialise vim to use the font with the given name. Return FAIL if the font | |
3775 * could not be loaded, OK otherwise. | |
3776 */ | |
3777 int | |
3778 gui_mch_init_font( | |
3779 char_u *font_name, | |
3780 int fontset) | |
3781 { | |
3782 if (gui.vimWindow->Lock()) | |
3783 { | |
3784 int rc = gui.vimTextArea->mchInitFont(font_name); | |
3785 gui.vimWindow->Unlock(); | |
3786 | |
3787 return rc; | |
3788 } | |
3789 | |
3790 return FAIL; | |
3791 } | |
3792 | |
3793 | |
3794 int | |
3795 gui_mch_adjust_charsize() | |
3796 { | |
3797 return FAIL; | |
3798 } | |
3799 | |
3800 | |
3801 int | |
3802 gui_mch_font_dialog(font_family* family, font_style* style, float* size) | |
3803 { | |
3804 #if defined(FEAT_GUI_DIALOG) | |
3805 // gui.vimWindow->Unlock(); | |
3806 VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size); | |
3807 return dialog->Go(); | |
3808 #else | |
3809 return NOFONT; | |
3810 #endif // FEAT_GUI_DIALOG | |
3811 } | |
3812 | |
3813 | |
3814 GuiFont | |
3815 gui_mch_get_font( | |
3816 char_u *name, | |
3817 int giveErrorIfMissing) | |
3818 { | |
3819 static VimFont *fontList = NULL; | |
3820 | |
3821 if (!gui.in_use) // can't do this when GUI not running | |
3822 return NOFONT; | |
3823 | |
3824 // storage for locally modified name; | |
3825 const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20; | |
3826 static char font_name[buff_size] = {0}; | |
3827 font_family family = {0}; | |
3828 font_style style = {0}; | |
3829 float size = 0.f; | |
3830 | |
3831 if (name == 0 && be_fixed_font == 0) { | |
3832 if(giveErrorIfMissing) | |
3833 semsg(_(e_font), name); | |
3834 return NOFONT; | |
3835 } | |
3836 | |
3837 bool useSelectGUI = false; | |
3838 if (name != NULL) | |
3839 if (STRCMP(name, "*") == 0) { | |
3840 useSelectGUI = true; | |
3841 STRNCPY(font_name, hl_get_font_name(), buff_size); | |
3842 } else | |
3843 STRNCPY(font_name, name, buff_size); | |
3844 | |
3845 if (font_name[0] == 0) { | |
3846 be_fixed_font->GetFamilyAndStyle(&family, &style); | |
3847 size = be_fixed_font->Size(); | |
3848 vim_snprintf(font_name, buff_size, | |
3849 (char*)"%s/%s/%.0f", family, style, size); | |
3850 } | |
3851 | |
3852 // replace underscores with spaces | |
3853 char* end = 0; | |
3854 while (end = strchr((char *)font_name, '_')) | |
3855 *end = ' '; | |
3856 | |
3857 // store the name before strtok corrupt the buffer ;-) | |
3858 static char buff[buff_size] = {0}; | |
3859 STRNCPY(buff, font_name, buff_size); | |
3860 STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH); | |
3861 char* style_s = strtok(0, "/\0"); | |
3862 if (style_s != 0) | |
3863 STRNCPY(style, style_s, B_FONT_STYLE_LENGTH); | |
3864 size = atof((style_s != 0) ? strtok(0, "/\0") : "0"); | |
3865 | |
3866 if (useSelectGUI) { | |
3867 if(gui_mch_font_dialog(&family, &style, &size) == NOFONT) | |
3868 return FAIL; | |
3869 // compose for further processing | |
3870 vim_snprintf(font_name, buff_size, | |
3871 (char*)"%s/%s/%.0f", family, style, size); | |
3872 hl_set_font_name((char_u*)font_name); | |
3873 | |
3874 // Set guifont to the name of the selected font. | |
20134
352701a626ed
patch 8.2.0622: Haiku: GUI does not compile
Bram Moolenaar <Bram@vim.org>
parents:
19526
diff
changeset
|
3875 char_u* new_p_guifont = (char_u*)alloc(STRLEN(font_name) + 1); |
19526 | 3876 if (new_p_guifont != NULL) { |
3877 STRCPY(new_p_guifont, font_name); | |
3878 vim_free(p_guifont); | |
3879 p_guifont = new_p_guifont; | |
3880 // Replace spaces in the font name with underscores. | |
3881 for ( ; *new_p_guifont; ++new_p_guifont) | |
3882 if (*new_p_guifont == ' ') | |
3883 *new_p_guifont = '_'; | |
3884 } | |
3885 } | |
3886 | |
3887 VimFont *flp; | |
3888 for (flp = fontList; flp; flp = flp->next) { | |
3889 if (STRCMP(font_name, flp->name) == 0) { | |
3890 flp->refcount++; | |
3891 return (GuiFont)flp; | |
3892 } | |
3893 } | |
3894 | |
3895 VimFont *font = new VimFont(); | |
3896 font->name = vim_strsave((char_u*)font_name); | |
3897 | |
3898 if(count_font_styles(family) <= 0) { | |
3899 if (giveErrorIfMissing) | |
3900 semsg(_(e_font), font->name); | |
3901 delete font; | |
3902 return NOFONT; | |
3903 } | |
3904 | |
3905 // Remember font in the static list for later use | |
3906 font->next = fontList; | |
3907 fontList = font; | |
3908 | |
3909 font->SetFamilyAndStyle(family, style); | |
3910 if(size > 0.f) | |
3911 font->SetSize(size); | |
3912 | |
3913 font->SetSpacing(B_FIXED_SPACING); | |
3914 font->SetEncoding(B_UNICODE_UTF8); | |
3915 | |
3916 return (GuiFont)font; | |
3917 } | |
3918 | |
3919 /* | |
3920 * Set the current text font. | |
3921 */ | |
3922 void | |
3923 gui_mch_set_font( | |
3924 GuiFont font) | |
3925 { | |
3926 if (gui.vimWindow->Lock()) { | |
3927 VimFont *vf = (VimFont *)font; | |
3928 | |
3929 gui.vimTextArea->SetFont(vf); | |
3930 | |
3931 gui.char_width = (int) vf->StringWidth("n"); | |
3932 font_height fh; | |
3933 vf->GetHeight(&fh); | |
3934 gui.char_height = (int)(fh.ascent + 0.9999) | |
3935 + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999); | |
3936 gui.char_ascent = (int)(fh.ascent + 0.9999); | |
3937 | |
3938 gui.vimWindow->Unlock(); | |
3939 } | |
3940 } | |
3941 | |
3942 // XXX TODO This is apparently never called... | |
3943 void | |
3944 gui_mch_free_font( | |
3945 GuiFont font) | |
3946 { | |
3947 if(font == NOFONT) | |
3948 return; | |
3949 VimFont *f = (VimFont *)font; | |
3950 if (--f->refcount <= 0) { | |
3951 if (f->refcount < 0) | |
3952 fprintf(stderr, "VimFont: refcount < 0\n"); | |
3953 delete f; | |
3954 } | |
3955 } | |
3956 | |
3957 char_u * | |
3958 gui_mch_get_fontname(GuiFont font, char_u *name) | |
3959 { | |
3960 if (name == NULL) | |
3961 return NULL; | |
3962 return vim_strsave(name); | |
3963 } | |
3964 | |
3965 /* | |
3966 * Adjust gui.char_height (after 'linespace' was changed). | |
3967 */ | |
3968 int | |
3969 gui_mch_adjust_charheight() | |
3970 { | |
3971 | |
3972 // TODO: linespace support? | |
3973 | |
3974 // #ifdef FEAT_XFONTSET | |
3975 // if (gui.fontset != NOFONTSET) | |
3976 // { | |
3977 // gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace; | |
3978 // gui.char_ascent = fontset_ascent((XFontSet)gui.fontset) | |
3979 // + p_linespace / 2; | |
3980 // } | |
3981 // else | |
3982 // #endif | |
3983 { | |
3984 VimFont *font = (VimFont *)gui.norm_font; | |
3985 font_height fh = {0}; | |
3986 font->GetHeight(&fh); | |
3987 gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace; | |
3988 gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2; | |
3989 } | |
3990 return OK; | |
3991 } | |
3992 | |
3993 /* | |
3994 * Display the saved error message(s). | |
3995 */ | |
3996 #ifdef USE_MCH_ERRMSG | |
3997 void | |
3998 display_errors(void) | |
3999 { | |
4000 char *p; | |
4001 char_u pError[256]; | |
4002 | |
4003 if (error_ga.ga_data == NULL) | |
4004 return; | |
4005 | |
4006 // avoid putting up a message box with blanks only | |
4007 for (p = (char *)error_ga.ga_data; *p; ++p) | |
4008 if (!isspace(*p)) | |
4009 { | |
4010 if (STRLEN(p) > 255) | |
4011 pError[0] = 255; | |
4012 else | |
4013 pError[0] = STRLEN(p); | |
4014 | |
4015 STRNCPY(&pError[1], p, pError[0]); | |
4016 // ParamText(pError, nil, nil, nil); | |
4017 // Alert(128, nil); | |
4018 break; | |
4019 // TODO: handled message longer than 256 chars | |
4020 // use auto-sizeable alert | |
4021 // or dialog with scrollbars (TextEdit zone) | |
4022 } | |
4023 ga_clear(&error_ga); | |
4024 } | |
4025 #endif | |
4026 | |
4027 void | |
4028 gui_mch_getmouse(int *x, int *y) | |
4029 { | |
4030 fprintf(stderr, "gui_mch_getmouse"); | |
4031 | |
4032 /*int rootx, rooty, winx, winy; | |
4033 Window root, child; | |
4034 unsigned int mask; | |
4035 | |
4036 if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child, | |
4037 &rootx, &rooty, &winx, &winy, &mask)) { | |
4038 *x = winx; | |
4039 *y = winy; | |
4040 } else*/ { | |
4041 *x = -1; | |
4042 *y = -1; | |
4043 } | |
4044 } | |
4045 | |
4046 void | |
4047 gui_mch_mousehide(int hide) | |
4048 { | |
4049 fprintf(stderr, "gui_mch_getmouse"); | |
4050 // TODO | |
4051 } | |
4052 | |
4053 static int | |
4054 hex_digit(int c) | |
4055 { | |
4056 if (isdigit(c)) | |
4057 return c - '0'; | |
4058 c = TOLOWER_ASC(c); | |
4059 if (c >= 'a' && c <= 'f') | |
4060 return c - 'a' + 10; | |
4061 return -1000; | |
4062 } | |
4063 | |
4064 /* | |
4065 * This function has been lifted from gui_w32.c and extended a bit. | |
4066 * | |
4067 * Return the Pixel value (color) for the given color name. | |
4068 * Return INVALCOLOR for error. | |
4069 */ | |
4070 guicolor_T | |
4071 gui_mch_get_color( | |
4072 char_u *name) | |
4073 { | |
4074 typedef struct GuiColourTable | |
4075 { | |
4076 const char *name; | |
4077 guicolor_T colour; | |
4078 } GuiColourTable; | |
4079 | |
4080 #define NSTATIC_COLOURS 50 // 32 | |
4081 #define NDYNAMIC_COLOURS 33 | |
4082 #define NCOLOURS (NSTATIC_COLOURS + NDYNAMIC_COLOURS) | |
4083 | |
4084 static GuiColourTable table[NCOLOURS] = | |
4085 { | |
4086 {"Black", RGB(0x00, 0x00, 0x00)}, | |
4087 {"DarkGray", RGB(0x80, 0x80, 0x80)}, | |
4088 {"DarkGrey", RGB(0x80, 0x80, 0x80)}, | |
4089 {"Gray", RGB(0xC0, 0xC0, 0xC0)}, | |
4090 {"Grey", RGB(0xC0, 0xC0, 0xC0)}, | |
4091 {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, | |
4092 {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, | |
4093 {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, | |
4094 {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, | |
4095 {"Gray20", RGB(0x33, 0x33, 0x33)}, | |
4096 {"Grey20", RGB(0x33, 0x33, 0x33)}, | |
4097 {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, | |
4098 {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, | |
4099 {"Gray40", RGB(0x66, 0x66, 0x66)}, | |
4100 {"Grey40", RGB(0x66, 0x66, 0x66)}, | |
4101 {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, | |
4102 {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, | |
4103 {"Gray60", RGB(0x99, 0x99, 0x99)}, | |
4104 {"Grey60", RGB(0x99, 0x99, 0x99)}, | |
4105 {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, | |
4106 {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, | |
4107 {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, | |
4108 {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, | |
4109 {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, | |
4110 {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, | |
4111 {"White", RGB(0xFF, 0xFF, 0xFF)}, | |
4112 {"DarkRed", RGB(0x80, 0x00, 0x00)}, | |
4113 {"Red", RGB(0xFF, 0x00, 0x00)}, | |
4114 {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, | |
4115 {"DarkBlue", RGB(0x00, 0x00, 0x80)}, | |
4116 {"Blue", RGB(0x00, 0x00, 0xFF)}, | |
4117 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)}, | |
4118 {"DarkGreen", RGB(0x00, 0x80, 0x00)}, | |
4119 {"Green", RGB(0x00, 0xFF, 0x00)}, | |
4120 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)}, | |
4121 {"DarkCyan", RGB(0x00, 0x80, 0x80)}, | |
4122 {"Cyan", RGB(0x00, 0xFF, 0xFF)}, | |
4123 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)}, | |
4124 {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, | |
4125 {"Magenta", RGB(0xFF, 0x00, 0xFF)}, | |
4126 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, | |
4127 {"Brown", RGB(0x80, 0x40, 0x40)}, | |
4128 {"Yellow", RGB(0xFF, 0xFF, 0x00)}, | |
4129 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)}, | |
4130 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)}, | |
4131 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, | |
4132 {"Orange", RGB(0xFF, 0xA5, 0x00)}, | |
4133 {"Purple", RGB(0xA0, 0x20, 0xF0)}, | |
4134 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, | |
4135 {"Violet", RGB(0xEE, 0x82, 0xEE)}, | |
4136 // NOTE: some entries are zero-allocated for NDDYNAMIC_COLORS | |
4137 // in this table! | |
4138 }; | |
4139 | |
4140 static int endColour = NSTATIC_COLOURS; | |
4141 static int newColour = NSTATIC_COLOURS; | |
4142 | |
4143 int r, g, b; | |
4144 int i; | |
4145 | |
4146 if (name[0] == '#' && STRLEN(name) == 7) | |
4147 { | |
4148 // Name is in "#rrggbb" format | |
4149 r = hex_digit(name[1]) * 16 + hex_digit(name[2]); | |
4150 g = hex_digit(name[3]) * 16 + hex_digit(name[4]); | |
4151 b = hex_digit(name[5]) * 16 + hex_digit(name[6]); | |
4152 if (r < 0 || g < 0 || b < 0) | |
4153 return INVALCOLOR; | |
4154 return RGB(r, g, b); | |
4155 } | |
4156 else | |
4157 { | |
4158 // Check if the name is one of the colours we know | |
4159 for (i = 0; i < endColour; i++) | |
4160 if (STRICMP(name, table[i].name) == 0) | |
4161 return table[i].colour; | |
4162 } | |
4163 | |
4164 /* | |
4165 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". | |
4166 */ | |
4167 { | |
4168 #define LINE_LEN 100 | |
4169 FILE *fd; | |
4170 char line[LINE_LEN]; | |
4171 char_u *fname; | |
4172 | |
4173 fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); | |
4174 if (fname == NULL) | |
4175 return INVALCOLOR; | |
4176 | |
4177 fd = fopen((char *)fname, "rt"); | |
4178 vim_free(fname); | |
4179 if (fd == NULL) | |
4180 return INVALCOLOR; | |
4181 | |
4182 while (!feof(fd)) | |
4183 { | |
4184 int len; | |
4185 int pos; | |
4186 char *colour; | |
4187 | |
4188 fgets(line, LINE_LEN, fd); | |
4189 len = strlen(line); | |
4190 | |
4191 if (len <= 1 || line[len-1] != '\n') | |
4192 continue; | |
4193 | |
4194 line[len-1] = '\0'; | |
4195 | |
4196 i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); | |
4197 if (i != 3) | |
4198 continue; | |
4199 | |
4200 colour = line + pos; | |
4201 | |
4202 if (STRICMP(colour, name) == 0) | |
4203 { | |
4204 fclose(fd); | |
4205 /* | |
4206 * Now remember this colour in the table. | |
4207 * A LRU scheme might be better but this is simpler. | |
4208 * Or could use a growing array. | |
4209 */ | |
4210 guicolor_T gcolour = RGB(r,g,b); | |
4211 | |
4212 // NOTE: see note above in table allocation! We are working here with | |
4213 // dynamically allocated names, not constant ones! | |
4214 vim_free((char*)table[newColour].name); | |
4215 table[newColour].name = (char *)vim_strsave((char_u *)colour); | |
4216 table[newColour].colour = gcolour; | |
4217 | |
4218 newColour++; | |
4219 if (newColour >= NCOLOURS) | |
4220 newColour = NSTATIC_COLOURS; | |
4221 if (endColour < NCOLOURS) | |
4222 endColour = newColour; | |
4223 | |
4224 return gcolour; | |
4225 } | |
4226 } | |
4227 | |
4228 fclose(fd); | |
4229 } | |
4230 | |
4231 return INVALCOLOR; | |
4232 } | |
4233 | |
4234 /* | |
4235 * Set the current text foreground color. | |
4236 */ | |
4237 void | |
4238 gui_mch_set_fg_color( | |
4239 guicolor_T color) | |
4240 { | |
4241 rgb_color rgb = GUI_TO_RGB(color); | |
4242 if (gui.vimWindow->Lock()) { | |
4243 gui.vimTextArea->SetHighColor(rgb); | |
4244 gui.vimWindow->Unlock(); | |
4245 } | |
4246 } | |
4247 | |
4248 /* | |
4249 * Set the current text background color. | |
4250 */ | |
4251 void | |
4252 gui_mch_set_bg_color( | |
4253 guicolor_T color) | |
4254 { | |
4255 rgb_color rgb = GUI_TO_RGB(color); | |
4256 if (gui.vimWindow->Lock()) { | |
4257 gui.vimTextArea->SetLowColor(rgb); | |
4258 gui.vimWindow->Unlock(); | |
4259 } | |
4260 } | |
4261 | |
4262 /* | |
4263 * Set the current text special color. | |
4264 */ | |
4265 void | |
4266 gui_mch_set_sp_color(guicolor_T color) | |
4267 { | |
4268 // prev_sp_color = color; | |
4269 } | |
4270 | |
4271 void | |
4272 gui_mch_draw_string( | |
4273 int row, | |
4274 int col, | |
4275 char_u *s, | |
4276 int len, | |
4277 int flags) | |
4278 { | |
4279 if (gui.vimWindow->Lock()) { | |
4280 gui.vimTextArea->mchDrawString(row, col, s, len, flags); | |
4281 gui.vimWindow->Unlock(); | |
4282 } | |
4283 } | |
4284 | |
4285 guicolor_T | |
4286 gui_mch_get_rgb_color(int r, int g, int b) | |
4287 { | |
4288 return gui_get_rgb_color_cmn(r, g, b); | |
4289 } | |
4290 | |
4291 | |
4292 // Return OK if the key with the termcap name "name" is supported. | |
4293 int | |
4294 gui_mch_haskey( | |
4295 char_u *name) | |
4296 { | |
4297 int i; | |
4298 | |
4299 for (i = 0; special_keys[i].BeKeys != 0; i++) | |
4300 if (name[0] == special_keys[i].vim_code0 && | |
4301 name[1] == special_keys[i].vim_code1) | |
4302 return OK; | |
4303 return FAIL; | |
4304 } | |
4305 | |
4306 void | |
4307 gui_mch_beep() | |
4308 { | |
4309 ::beep(); | |
4310 } | |
4311 | |
4312 void | |
4313 gui_mch_flash(int msec) | |
4314 { | |
4315 // Do a visual beep by reversing the foreground and background colors | |
4316 | |
4317 if (gui.vimWindow->Lock()) { | |
4318 BRect rect = gui.vimTextArea->Bounds(); | |
4319 | |
4320 gui.vimTextArea->SetDrawingMode(B_OP_INVERT); | |
4321 gui.vimTextArea->FillRect(rect); | |
4322 gui.vimTextArea->Sync(); | |
4323 snooze(msec * 1000); // wait for a few msec | |
4324 gui.vimTextArea->FillRect(rect); | |
4325 gui.vimTextArea->SetDrawingMode(B_OP_COPY); | |
4326 gui.vimTextArea->Flush(); | |
4327 gui.vimWindow->Unlock(); | |
4328 } | |
4329 } | |
4330 | |
4331 /* | |
4332 * Invert a rectangle from row r, column c, for nr rows and nc columns. | |
4333 */ | |
4334 void | |
4335 gui_mch_invert_rectangle( | |
4336 int r, | |
4337 int c, | |
4338 int nr, | |
4339 int nc) | |
4340 { | |
4341 BRect rect; | |
4342 rect.left = FILL_X(c); | |
4343 rect.top = FILL_Y(r); | |
4344 rect.right = rect.left + nc * gui.char_width - PEN_WIDTH; | |
4345 rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH; | |
4346 | |
4347 if (gui.vimWindow->Lock()) { | |
4348 gui.vimTextArea->SetDrawingMode(B_OP_INVERT); | |
4349 gui.vimTextArea->FillRect(rect); | |
4350 gui.vimTextArea->SetDrawingMode(B_OP_COPY); | |
4351 gui.vimWindow->Unlock(); | |
4352 } | |
4353 } | |
4354 | |
4355 /* | |
4356 * Iconify the GUI window. | |
4357 */ | |
4358 void | |
4359 gui_mch_iconify() | |
4360 { | |
4361 if (gui.vimWindow->Lock()) { | |
4362 gui.vimWindow->Minimize(true); | |
4363 gui.vimWindow->Unlock(); | |
4364 } | |
4365 } | |
4366 | |
4367 #if defined(FEAT_EVAL) || defined(PROTO) | |
4368 /* | |
4369 * Bring the Vim window to the foreground. | |
4370 */ | |
4371 void | |
4372 gui_mch_set_foreground(void) | |
4373 { | |
4374 // TODO | |
4375 } | |
4376 #endif | |
4377 | |
4378 /* | |
4379 * Set the window title | |
4380 */ | |
4381 void | |
4382 gui_mch_settitle( | |
4383 char_u *title, | |
4384 char_u *icon) | |
4385 { | |
4386 if (gui.vimWindow->Lock()) { | |
4387 gui.vimWindow->SetTitle((char *)title); | |
4388 gui.vimWindow->Unlock(); | |
4389 } | |
4390 } | |
4391 | |
4392 /* | |
4393 * Draw a cursor without focus. | |
4394 */ | |
4395 void | |
4396 gui_mch_draw_hollow_cursor(guicolor_T color) | |
4397 { | |
4398 gui_mch_set_fg_color(color); | |
4399 | |
4400 BRect r; | |
4401 r.left = FILL_X(gui.col); | |
4402 r.top = FILL_Y(gui.row); | |
4403 int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO | |
4404 if(cells>=4) cells = 1; | |
4405 r.right = r.left + cells*gui.char_width - PEN_WIDTH; | |
4406 r.bottom = r.top + gui.char_height - PEN_WIDTH; | |
4407 | |
4408 if (gui.vimWindow->Lock()) { | |
4409 gui.vimTextArea->StrokeRect(r); | |
4410 gui.vimWindow->Unlock(); | |
4411 // gui_mch_flush(); | |
4412 } | |
4413 } | |
4414 | |
4415 /* | |
4416 * Draw part of a cursor, only w pixels wide, and h pixels high. | |
4417 */ | |
4418 void | |
4419 gui_mch_draw_part_cursor( | |
4420 int w, | |
4421 int h, | |
4422 guicolor_T color) | |
4423 { | |
4424 gui_mch_set_fg_color(color); | |
4425 | |
4426 BRect r; | |
4427 r.left = | |
4428 #ifdef FEAT_RIGHTLEFT | |
4429 // vertical line should be on the right of current point | |
4430 CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : | |
4431 #endif | |
4432 FILL_X(gui.col); | |
4433 r.right = r.left + w - PEN_WIDTH; | |
4434 r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH; | |
4435 r.top = r.bottom - h + PEN_WIDTH; | |
4436 | |
4437 if (gui.vimWindow->Lock()) { | |
4438 gui.vimTextArea->FillRect(r); | |
4439 gui.vimWindow->Unlock(); | |
4440 // gui_mch_flush(); | |
4441 } | |
4442 } | |
4443 | |
4444 /* | |
4445 * Catch up with any queued events. This may put keyboard input into the | |
4446 * input buffer, call resize call-backs, trigger timers etc. If there is | |
4447 * nothing in the event queue (& no timers pending), then we return | |
4448 * immediately. | |
4449 */ | |
4450 void | |
4451 gui_mch_update() | |
4452 { | |
4453 gui_mch_flush(); | |
4454 while (port_count(gui.vdcmp) > 0 && | |
4455 !vim_is_input_buf_full() && | |
4456 gui_haiku_process_event(0) >= B_OK) | |
4457 /* nothing */ ; | |
4458 } | |
4459 | |
4460 /* | |
4461 * GUI input routine called by gui_wait_for_chars(). Waits for a character | |
4462 * from the keyboard. | |
4463 * wtime == -1 Wait forever. | |
4464 * wtime == 0 This should never happen. | |
4465 * wtime > 0 Wait wtime milliseconds for a character. | |
4466 * Returns OK if a character was found to be available within the given time, | |
4467 * or FAIL otherwise. | |
4468 */ | |
4469 int | |
4470 gui_mch_wait_for_chars( | |
4471 int wtime) | |
4472 { | |
4473 int focus; | |
4474 bigtime_t until, timeout; | |
4475 status_t st; | |
4476 | |
4477 if (wtime >= 0) { | |
4478 timeout = wtime * 1000; | |
4479 until = system_time() + timeout; | |
4480 } else { | |
4481 timeout = B_INFINITE_TIMEOUT; | |
4482 } | |
4483 | |
4484 focus = gui.in_focus; | |
4485 for (;;) | |
4486 { | |
4487 // Stop or start blinking when focus changes | |
4488 if (gui.in_focus != focus) | |
4489 { | |
4490 if (gui.in_focus) | |
4491 gui_mch_start_blink(); | |
4492 else | |
20134
352701a626ed
patch 8.2.0622: Haiku: GUI does not compile
Bram Moolenaar <Bram@vim.org>
parents:
19526
diff
changeset
|
4493 gui_mch_stop_blink(TRUE); |
19526 | 4494 focus = gui.in_focus; |
4495 } | |
4496 | |
4497 gui_mch_flush(); | |
4498 /* | |
4499 * Don't use gui_mch_update() because then we will spin-lock until a | |
4500 * char arrives, instead we use gui_haiku_process_event() to hang until | |
4501 * an event arrives. No need to check for input_buf_full because we | |
4502 * are returning as soon as it contains a single char. | |
4503 */ | |
4504 st = gui_haiku_process_event(timeout); | |
4505 | |
4506 if (input_available()) | |
4507 return OK; | |
4508 if (st < B_OK) // includes B_TIMED_OUT | |
4509 return FAIL; | |
4510 | |
4511 /* | |
4512 * Calculate how much longer we're willing to wait for the | |
4513 * next event. | |
4514 */ | |
4515 if (wtime >= 0) { | |
4516 timeout = until - system_time(); | |
4517 if (timeout < 0) | |
4518 break; | |
4519 } | |
4520 } | |
4521 return FAIL; | |
4522 | |
4523 } | |
4524 | |
4525 /* | |
4526 * Output routines. | |
4527 */ | |
4528 | |
4529 /* | |
4530 * Flush any output to the screen. This is typically called before | |
4531 * the app goes to sleep. | |
4532 */ | |
4533 void | |
4534 gui_mch_flush() | |
4535 { | |
4536 // does this need to lock the window? Apparently not but be safe. | |
4537 if (gui.vimWindow->Lock()) { | |
4538 gui.vimWindow->Flush(); | |
4539 gui.vimWindow->Unlock(); | |
4540 } | |
4541 return; | |
4542 } | |
4543 | |
4544 /* | |
4545 * Clear a rectangular region of the screen from text pos (row1, col1) to | |
4546 * (row2, col2) inclusive. | |
4547 */ | |
4548 void | |
4549 gui_mch_clear_block( | |
4550 int row1, | |
4551 int col1, | |
4552 int row2, | |
4553 int col2) | |
4554 { | |
4555 if (gui.vimWindow->Lock()) { | |
4556 gui.vimTextArea->mchClearBlock(row1, col1, row2, col2); | |
4557 gui.vimWindow->Unlock(); | |
4558 } | |
4559 } | |
4560 | |
4561 void | |
4562 gui_mch_clear_all() | |
4563 { | |
4564 if (gui.vimWindow->Lock()) { | |
4565 gui.vimTextArea->mchClearAll(); | |
4566 gui.vimWindow->Unlock(); | |
4567 } | |
4568 } | |
4569 | |
4570 /* | |
4571 * Delete the given number of lines from the given row, scrolling up any | |
4572 * text further down within the scroll region. | |
4573 */ | |
4574 void | |
4575 gui_mch_delete_lines( | |
4576 int row, | |
4577 int num_lines) | |
4578 { | |
4579 gui.vimTextArea->mchDeleteLines(row, num_lines); | |
4580 } | |
4581 | |
4582 /* | |
4583 * Insert the given number of lines before the given row, scrolling down any | |
4584 * following text within the scroll region. | |
4585 */ | |
4586 void | |
4587 gui_mch_insert_lines( | |
4588 int row, | |
4589 int num_lines) | |
4590 { | |
4591 gui.vimTextArea->mchInsertLines(row, num_lines); | |
4592 } | |
4593 | |
4594 #if defined(FEAT_MENU) || defined(PROTO) | |
4595 /* | |
4596 * Menu stuff. | |
4597 */ | |
4598 | |
4599 void | |
4600 gui_mch_enable_menu( | |
4601 int flag) | |
4602 { | |
4603 if (gui.vimWindow->Lock()) | |
4604 { | |
4605 BMenuBar *menubar = gui.vimForm->MenuBar(); | |
4606 menubar->SetEnabled(flag); | |
4607 gui.vimWindow->Unlock(); | |
4608 } | |
4609 } | |
4610 | |
4611 void | |
4612 gui_mch_set_menu_pos( | |
4613 int x, | |
4614 int y, | |
4615 int w, | |
4616 int h) | |
4617 { | |
4618 // It will be in the right place anyway | |
4619 } | |
4620 | |
4621 /* | |
4622 * Add a sub menu to the menu bar. | |
4623 */ | |
4624 void | |
4625 gui_mch_add_menu( | |
4626 vimmenu_T *menu, | |
4627 int idx) | |
4628 { | |
4629 vimmenu_T *parent = menu->parent; | |
4630 | |
4631 // popup menu - just create it unattached | |
4632 if (menu_is_popup(menu->name) && parent == NULL) { | |
4633 BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false); | |
4634 menu->submenu_id = popUpMenu; | |
4635 menu->id = NULL; | |
4636 return; | |
4637 } | |
4638 | |
4639 if (!menu_is_menubar(menu->name) | |
4640 || (parent != NULL && parent->submenu_id == NULL)) | |
4641 return; | |
4642 | |
4643 if (gui.vimWindow->Lock()) | |
4644 { | |
4645 // Major re-write of the menu code, it was failing with memory corruption when | |
4646 // we started loading multiple files (the Buffer menu) | |
4647 // | |
4648 // Note we don't use the preference values yet, all are inserted into the | |
4649 // menubar on a first come-first served basis... | |
4650 // | |
4651 // richard@whitequeen.com jul 99 | |
4652 | |
4653 BMenu *tmp; | |
4654 | |
4655 if ( parent ) | |
4656 tmp = parent->submenu_id; | |
4657 else | |
4658 tmp = gui.vimForm->MenuBar(); | |
4659 // make sure we don't try and add the same menu twice. The Buffers menu tries to | |
4660 // do this and Be starts to crash... | |
4661 | |
4662 if ( ! tmp->FindItem((const char *) menu->dname)) { | |
4663 | |
4664 BMenu *bmenu = new BMenu((char *)menu->dname); | |
4665 | |
4666 menu->submenu_id = bmenu; | |
4667 | |
4668 // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem | |
4669 tmp->AddItem(bmenu); | |
4670 | |
4671 // Now its safe to query the menu for the associated MenuItem.... | |
4672 menu->id = tmp->FindItem((const char *) menu->dname); | |
4673 | |
4674 } | |
4675 gui.vimWindow->Unlock(); | |
4676 } | |
4677 } | |
4678 | |
4679 void | |
4680 gui_mch_toggle_tearoffs(int enable) | |
4681 { | |
4682 // no tearoff menus | |
4683 } | |
4684 | |
4685 static BMessage * | |
4686 MenuMessage(vimmenu_T *menu) | |
4687 { | |
4688 BMessage *m = new BMessage('menu'); | |
4689 m->AddPointer("VimMenu", (void *)menu); | |
4690 | |
4691 return m; | |
4692 } | |
4693 | |
4694 /* | |
4695 * Add a menu item to a menu | |
4696 */ | |
4697 void | |
4698 gui_mch_add_menu_item( | |
4699 vimmenu_T *menu, | |
4700 int idx) | |
4701 { | |
4702 int mnemonic = 0; | |
4703 vimmenu_T *parent = menu->parent; | |
4704 | |
4705 // TODO: use menu->actext | |
4706 // This is difficult, since on Be, an accelerator must be a single char | |
4707 // and a lot of Vim ones are the standard VI commands. | |
4708 // | |
4709 // Punt for Now... | |
4710 // richard@whiequeen.com jul 99 | |
4711 if (gui.vimWindow->Lock()) | |
4712 { | |
4713 #ifdef FEAT_TOOLBAR | |
4714 if(menu_is_toolbar(parent->name)) { | |
4715 VimToolbar *toolbar = gui.vimForm->ToolBar(); | |
4716 if(toolbar != NULL) { | |
4717 toolbar->AddButton(idx, menu); | |
4718 } | |
4719 } else | |
4720 #endif | |
4721 | |
4722 if (parent->submenu_id != NULL || menu_is_popup(parent->name)) { | |
4723 if (menu_is_separator(menu->name)) { | |
4724 BSeparatorItem *item = new BSeparatorItem(); | |
4725 parent->submenu_id->AddItem(item); | |
4726 menu->id = item; | |
4727 menu->submenu_id = NULL; | |
4728 } | |
4729 else { | |
4730 BMenuItem *item = new BMenuItem((char *)menu->dname, | |
4731 MenuMessage(menu)); | |
4732 item->SetTarget(gui.vimTextArea); | |
4733 item->SetTrigger((char) menu->mnemonic); | |
4734 parent->submenu_id->AddItem(item); | |
4735 menu->id = item; | |
4736 menu->submenu_id = NULL; | |
4737 } | |
4738 } | |
4739 gui.vimWindow->Unlock(); | |
4740 } | |
4741 } | |
4742 | |
4743 /* | |
4744 * Destroy the machine specific menu widget. | |
4745 */ | |
4746 void | |
4747 gui_mch_destroy_menu( | |
4748 vimmenu_T *menu) | |
4749 { | |
4750 if (gui.vimWindow->Lock()) | |
4751 { | |
4752 #ifdef FEAT_TOOLBAR | |
4753 if(menu->parent && menu_is_toolbar(menu->parent->name)) { | |
4754 VimToolbar *toolbar = gui.vimForm->ToolBar(); | |
4755 if(toolbar != NULL) { | |
4756 toolbar->RemoveButton(menu); | |
4757 } | |
4758 } else | |
4759 #endif | |
4760 { | |
4761 assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0); | |
4762 /* | |
4763 * Detach this menu from its parent, so that it is not deleted | |
4764 * twice once we get to delete that parent. | |
4765 * Deleting a BMenuItem also deletes the associated BMenu, if any | |
4766 * (which does not have any items anymore since they were | |
4767 * removed and deleted before). | |
4768 */ | |
4769 BMenu *bmenu = menu->id->Menu(); | |
4770 if (bmenu) | |
4771 { | |
4772 bmenu->RemoveItem(menu->id); | |
4773 /* | |
4774 * If we removed the last item from the menu bar, | |
4775 * resize it out of sight. | |
4776 */ | |
4777 if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0) | |
4778 { | |
4779 bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN); | |
4780 } | |
4781 } | |
4782 delete menu->id; | |
4783 menu->id = NULL; | |
4784 menu->submenu_id = NULL; | |
4785 | |
4786 gui.menu_height = (int) gui.vimForm->MenuHeight(); | |
4787 } | |
4788 gui.vimWindow->Unlock(); | |
4789 } | |
4790 } | |
4791 | |
4792 /* | |
4793 * Make a menu either grey or not grey. | |
4794 */ | |
4795 void | |
4796 gui_mch_menu_grey( | |
4797 vimmenu_T *menu, | |
4798 int grey) | |
4799 { | |
4800 #ifdef FEAT_TOOLBAR | |
4801 if(menu->parent && menu_is_toolbar(menu->parent->name)) { | |
4802 if (gui.vimWindow->Lock()) { | |
4803 VimToolbar *toolbar = gui.vimForm->ToolBar(); | |
4804 if(toolbar != NULL) { | |
4805 toolbar->GrayButton(menu, grey); | |
4806 } | |
4807 gui.vimWindow->Unlock(); | |
4808 } | |
4809 } else | |
4810 #endif | |
4811 if (menu->id != NULL) | |
4812 menu->id->SetEnabled(!grey); | |
4813 } | |
4814 | |
4815 /* | |
4816 * Make menu item hidden or not hidden | |
4817 */ | |
4818 void | |
4819 gui_mch_menu_hidden( | |
4820 vimmenu_T *menu, | |
4821 int hidden) | |
4822 { | |
4823 if (menu->id != NULL) | |
4824 menu->id->SetEnabled(!hidden); | |
4825 } | |
4826 | |
4827 /* | |
4828 * This is called after setting all the menus to grey/hidden or not. | |
4829 */ | |
4830 void | |
4831 gui_mch_draw_menubar() | |
4832 { | |
4833 // Nothing to do in BeOS | |
4834 } | |
4835 | |
4836 void | |
4837 gui_mch_show_popupmenu(vimmenu_T *menu) | |
4838 { | |
4839 if (!menu_is_popup(menu->name) || menu->submenu_id == NULL) | |
4840 return; | |
4841 | |
4842 BPopUpMenu* popupMenu = dynamic_cast<BPopUpMenu*>(menu->submenu_id); | |
4843 if (popupMenu == NULL) | |
4844 return; | |
4845 | |
4846 BPoint point; | |
4847 if(gui.vimWindow->Lock()) { | |
4848 uint32 buttons = 0; | |
4849 gui.vimTextArea->GetMouse(&point, &buttons); | |
4850 gui.vimTextArea->ConvertToScreen(&point); | |
4851 gui.vimWindow->Unlock(); | |
4852 } | |
4853 popupMenu->Go(point, true); | |
4854 } | |
4855 | |
4856 #endif // FEAT_MENU | |
4857 | |
4858 // Mouse stuff | |
4859 | |
4860 #ifdef FEAT_CLIPBOARD | |
4861 /* | |
4862 * Clipboard stuff, for cutting and pasting text to other windows. | |
4863 */ | |
4864 char textplain[] = "text/plain"; | |
4865 char vimselectiontype[] = "application/x-vnd.Rhialto-Vim-selectiontype"; | |
4866 | |
4867 /* | |
4868 * Get the current selection and put it in the clipboard register. | |
4869 */ | |
4870 void | |
4871 clip_mch_request_selection(Clipboard_T *cbd) | |
4872 { | |
4873 if (be_clipboard->Lock()) | |
4874 { | |
4875 BMessage *m = be_clipboard->Data(); | |
4876 // m->PrintToStream(); | |
4877 | |
4878 char_u *string = NULL; | |
4879 ssize_t stringlen = -1; | |
4880 | |
4881 if (m->FindData(textplain, B_MIME_TYPE, | |
4882 (const void **)&string, &stringlen) == B_OK | |
4883 || m->FindString("text", (const char **)&string) == B_OK) | |
4884 { | |
4885 if (stringlen == -1) | |
4886 stringlen = STRLEN(string); | |
4887 | |
4888 int type; | |
4889 char *seltype; | |
4890 ssize_t seltypelen; | |
4891 | |
4892 /* | |
4893 * Try to get the special vim selection type first | |
4894 */ | |
4895 if (m->FindData(vimselectiontype, B_MIME_TYPE, | |
4896 (const void **)&seltype, &seltypelen) == B_OK) | |
4897 { | |
4898 switch (*seltype) | |
4899 { | |
4900 default: | |
4901 case 'L': type = MLINE; break; | |
4902 case 'C': type = MCHAR; break; | |
4903 #ifdef FEAT_VISUAL | |
4904 case 'B': type = MBLOCK; break; | |
4905 #endif | |
4906 } | |
4907 } | |
4908 else | |
4909 { | |
4910 // Otherwise use heuristic as documented | |
4911 type = memchr(string, stringlen, '\n') ? MLINE : MCHAR; | |
4912 } | |
4913 clip_yank_selection(type, string, (long)stringlen, cbd); | |
4914 } | |
4915 be_clipboard->Unlock(); | |
4916 } | |
4917 } | |
4918 /* | |
4919 * Make vim the owner of the current selection. | |
4920 */ | |
4921 void | |
4922 clip_mch_lose_selection(Clipboard_T *cbd) | |
4923 { | |
4924 // Nothing needs to be done here | |
4925 } | |
4926 | |
4927 /* | |
4928 * Make vim the owner of the current selection. Return OK upon success. | |
4929 */ | |
4930 int | |
4931 clip_mch_own_selection(Clipboard_T *cbd) | |
4932 { | |
4933 /* | |
4934 * Never actually own the clipboard. If another application sets the | |
4935 * clipboard, we don't want to think that we still own it. | |
4936 */ | |
4937 return FAIL; | |
4938 } | |
4939 | |
4940 /* | |
4941 * Send the current selection to the clipboard. | |
4942 */ | |
4943 void | |
4944 clip_mch_set_selection(Clipboard_T *cbd) | |
4945 { | |
4946 if (be_clipboard->Lock()) | |
4947 { | |
4948 be_clipboard->Clear(); | |
4949 BMessage *m = be_clipboard->Data(); | |
4950 assert(m); | |
4951 | |
4952 // If the '*' register isn't already filled in, fill it in now | |
4953 cbd->owned = TRUE; | |
4954 clip_get_selection(cbd); | |
4955 cbd->owned = FALSE; | |
4956 | |
4957 char_u *str = NULL; | |
4958 long_u count; | |
4959 int type; | |
4960 | |
4961 type = clip_convert_selection(&str, &count, cbd); | |
4962 | |
4963 if (type < 0) | |
4964 return; | |
4965 | |
4966 m->AddData(textplain, B_MIME_TYPE, (void *)str, count); | |
4967 | |
4968 // Add type of selection | |
4969 char vtype; | |
4970 switch (type) | |
4971 { | |
4972 default: | |
4973 case MLINE: vtype = 'L'; break; | |
4974 case MCHAR: vtype = 'C'; break; | |
4975 #ifdef FEAT_VISUAL | |
4976 case MBLOCK: vtype = 'B'; break; | |
4977 #endif | |
4978 } | |
4979 m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1); | |
4980 | |
4981 vim_free(str); | |
4982 | |
4983 be_clipboard->Commit(); | |
4984 be_clipboard->Unlock(); | |
4985 } | |
4986 } | |
4987 | |
4988 #endif // FEAT_CLIPBOARD | |
4989 | |
4990 #ifdef FEAT_BROWSE | |
4991 /* | |
4992 * Pop open a file browser and return the file selected, in allocated memory, | |
4993 * or NULL if Cancel is hit. | |
4994 * saving - TRUE if the file will be saved to, FALSE if it will be opened. | |
4995 * title - Title message for the file browser dialog. | |
4996 * dflt - Default name of file. | |
4997 * ext - Default extension to be added to files without extensions. | |
4998 * initdir - directory in which to open the browser (NULL = current dir) | |
4999 * filter - Filter for matched files to choose from. | |
5000 * Has a format like this: | |
5001 * "C Files (*.c)\0*.c\0" | |
5002 * "All Files\0*.*\0\0" | |
5003 * If these two strings were concatenated, then a choice of two file | |
5004 * filters will be selectable to the user. Then only matching files will | |
5005 * be shown in the browser. If NULL, the default allows all files. | |
5006 * | |
5007 * *NOTE* - the filter string must be terminated with TWO nulls. | |
5008 */ | |
5009 char_u * | |
5010 gui_mch_browse( | |
5011 int saving, | |
5012 char_u *title, | |
5013 char_u *dflt, | |
5014 char_u *ext, | |
5015 char_u *initdir, | |
5016 char_u *filter) | |
5017 { | |
5018 gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL, | |
5019 NULL, NULL, 0, false, | |
5020 new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true); | |
5021 | |
5022 gui.vimApp->fBrowsedPath.Unset(); | |
5023 | |
5024 gui.vimApp->fFilePanel->Window()->SetTitle((char*)title); | |
5025 gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir); | |
5026 | |
5027 gui.vimApp->fFilePanel->Show(); | |
5028 | |
5029 gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem"); | |
5030 | |
5031 while(acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED); | |
5032 | |
5033 char_u *fileName = NULL; | |
5034 status_t result = gui.vimApp->fBrowsedPath.InitCheck(); | |
5035 if(result == B_OK) { | |
5036 fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path()); | |
5037 } else | |
5038 if(result != B_NO_INIT) { | |
5039 fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n", | |
5040 result, strerror(result)); | |
5041 } | |
5042 | |
5043 delete gui.vimApp->fFilePanel; | |
5044 gui.vimApp->fFilePanel = NULL; | |
5045 | |
5046 return fileName; | |
5047 } | |
5048 #endif // FEAT_BROWSE | |
5049 | |
5050 | |
5051 #if defined(FEAT_GUI_DIALOG) | |
5052 | |
5053 /* | |
5054 * Create a dialog dynamically from the parameter strings. | |
5055 * type = type of dialog (question, alert, etc.) | |
5056 * title = dialog title. may be NULL for default title. | |
5057 * message = text to display. Dialog sizes to accommodate it. | |
5058 * buttons = '\n' separated list of button captions, default first. | |
5059 * dfltbutton = number of default button. | |
5060 * | |
5061 * This routine returns 1 if the first button is pressed, | |
5062 * 2 for the second, etc. | |
5063 * | |
5064 * 0 indicates Esc was pressed. | |
5065 * -1 for unexpected error | |
5066 * | |
5067 * If stubbing out this fn, return 1. | |
5068 */ | |
5069 | |
5070 int | |
5071 gui_mch_dialog( | |
5072 int type, | |
5073 char_u *title, | |
5074 char_u *message, | |
5075 char_u *buttons, | |
5076 int dfltbutton, | |
5077 char_u *textfield, | |
5078 int ex_cmd) | |
5079 { | |
5080 VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message, | |
5081 (char*)buttons, dfltbutton, (char*)textfield, ex_cmd); | |
5082 return dialog->Go(); | |
5083 } | |
5084 | |
5085 #endif // FEAT_GUI_DIALOG | |
5086 | |
5087 | |
5088 /* | |
5089 * Return the RGB value of a pixel as long. | |
5090 */ | |
5091 guicolor_T | |
5092 gui_mch_get_rgb(guicolor_T pixel) | |
5093 { | |
5094 rgb_color rgb = GUI_TO_RGB(pixel); | |
5095 | |
5096 return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8) | |
5097 + (rgb.blue & 0xff); | |
5098 } | |
5099 | |
5100 void | |
5101 gui_mch_setmouse(int x, int y) | |
5102 { | |
5103 TRACE(); | |
5104 // TODO | |
5105 } | |
5106 | |
5107 #ifdef FEAT_MBYTE_IME | |
5108 void | |
5109 im_set_position(int row, int col) | |
5110 { | |
5111 if(gui.vimWindow->Lock()) | |
5112 { | |
5113 gui.vimTextArea->DrawIMString(); | |
5114 gui.vimWindow->Unlock(); | |
5115 } | |
5116 return; | |
5117 } | |
5118 #endif | |
5119 | |
5120 void | |
5121 gui_mch_show_toolbar(int showit) | |
5122 { | |
5123 VimToolbar *toolbar = gui.vimForm->ToolBar(); | |
5124 gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.; | |
5125 } | |
5126 | |
5127 void | |
5128 gui_mch_set_toolbar_pos(int x, int y, int w, int h) | |
5129 { | |
5130 VimToolbar *toolbar = gui.vimForm->ToolBar(); | |
5131 if(toolbar != NULL) { | |
5132 if (gui.vimWindow->Lock()) { | |
5133 toolbar->MoveTo(x, y); | |
5134 toolbar->ResizeTo(w - 1, h - 1); | |
5135 gui.vimWindow->Unlock(); | |
5136 } | |
5137 } | |
5138 } | |
5139 | |
5140 #if defined(FEAT_GUI_TABLINE) || defined(PROTO) | |
5141 | |
5142 /* | |
5143 * Show or hide the tabline. | |
5144 */ | |
5145 void | |
5146 gui_mch_show_tabline(int showit) | |
5147 { | |
5148 VimTabLine *tabLine = gui.vimForm->TabLine(); | |
5149 | |
5150 if (tabLine == NULL) | |
5151 return; | |
5152 | |
5153 if (!showit != !gui.vimForm->IsShowingTabLine()) { | |
5154 gui.vimForm->SetShowingTabLine(showit != 0); | |
5155 gui.tabline_height = gui.vimForm->TablineHeight(); | |
5156 } | |
5157 } | |
5158 | |
5159 void | |
5160 gui_mch_set_tabline_pos(int x, int y, int w, int h) | |
5161 { | |
5162 VimTabLine *tabLine = gui.vimForm->TabLine(); | |
5163 if(tabLine != NULL) { | |
5164 if (gui.vimWindow->Lock()) { | |
5165 tabLine->MoveTo(x, y); | |
5166 tabLine->ResizeTo(w - 1, h - 1); | |
5167 gui.vimWindow->Unlock(); | |
5168 } | |
5169 } | |
5170 } | |
5171 | |
5172 /* | |
5173 * Return TRUE when tabline is displayed. | |
5174 */ | |
5175 int | |
5176 gui_mch_showing_tabline() | |
5177 { | |
5178 VimTabLine *tabLine = gui.vimForm->TabLine(); | |
5179 return tabLine != NULL && gui.vimForm->IsShowingTabLine(); | |
5180 } | |
5181 | |
5182 /* | |
5183 * Update the labels of the tabline. | |
5184 */ | |
5185 void | |
5186 gui_mch_update_tabline() | |
5187 { | |
5188 tabpage_T *tp; | |
5189 int nr = 0; | |
5190 int curtabidx = 0; | |
5191 | |
5192 VimTabLine *tabLine = gui.vimForm->TabLine(); | |
5193 | |
5194 if (tabLine == NULL) | |
5195 return; | |
5196 | |
5197 gui.vimWindow->Lock(); | |
5198 | |
5199 // Add a label for each tab page. They all contain the same text area. | |
5200 for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) { | |
5201 if (tp == curtab) | |
5202 curtabidx = nr; | |
5203 | |
5204 BTab* tab = tabLine->TabAt(nr); | |
5205 | |
5206 if (tab == NULL) { | |
5207 tab = new VimTabLine::VimTab(); | |
5208 tabLine->AddTab(NULL, tab); | |
5209 } | |
5210 | |
5211 get_tabline_label(tp, FALSE); | |
5212 tab->SetLabel((const char*)NameBuff); | |
5213 tabLine->Invalidate(); | |
5214 } | |
5215 | |
5216 // Remove any old labels. | |
5217 while (nr < tabLine->CountTabs()) | |
5218 tabLine->RemoveTab(nr); | |
5219 | |
5220 if(tabLine->Selection() != curtabidx) | |
5221 tabLine->Select(curtabidx); | |
5222 | |
5223 gui.vimWindow->Unlock(); | |
5224 } | |
5225 | |
5226 /* | |
5227 * Set the current tab to "nr". First tab is 1. | |
5228 */ | |
5229 void | |
5230 gui_mch_set_curtab(int nr) | |
5231 { | |
5232 VimTabLine *tabLine = gui.vimForm->TabLine(); | |
5233 if(tabLine == NULL) | |
5234 return; | |
5235 | |
5236 gui.vimWindow->Lock(); | |
5237 | |
5238 if(tabLine->Selection() != nr -1) | |
5239 tabLine->Select(nr -1); | |
5240 | |
5241 gui.vimWindow->Unlock(); | |
5242 } | |
5243 | |
5244 #endif // FEAT_GUI_TABLINE |