1 /** FXScintilla source code edit control
2  *
3  *  ScintillaFOX.cxx - FOX toolkit specific subclass of ScintillaBase
4  *
5  *  Copyright 2001-2004 by Gilles Filippini <gilles.filippini@free.fr>
6  *
7  *  Adapted from the Scintilla source ScintillaGTK.cxx
8  *  Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
9  *
10  *  ====================================================================
11  *
12  *  This file is part of FXScintilla.
13  *
14  *  FXScintilla is free software; you can redistribute it and/or modify
15  *  it under the terms of the GNU Lesser General Public License as published by
16  *  the Free Software Foundation; either version 2.1 of the License, or
17  *  (at your option) any later version.
18  *
19  *  FXScintilla is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU Lesser General Public License for more details.
23  *
24  *  You should have received a copy of the GNU Lesser General Public License
25  *  along with FXScintilla; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  **/
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <time.h>
34 #include <string>
35 #include <vector>
36 #include <map>
37 #include <algorithm>
38 
39 #if !defined(WIN32) || defined(__CYGWIN__)
40 # if defined(__CYGWIN__)
41 #  include <windows.h>
42 #  ifdef PIC
43 #   define FOXDLL
44 #  endif
45 # endif
46 # include <fx.h>
47 # include <fxkeys.h>
48 #else
49 # if defined(__MINGW32__)
50 #  include <windows.h>
51 #  if defined(PIC) && !defined(FOXDLL)
52 #    define FOXDLL
53 #  endif
54 # endif
55 # include <fx.h>
56 # include <fxkeys.h>
57 #endif  // !defined(WIN32) || defined(__CYGWIN__)
58 
59 #include "Platform.h"
60 
61 #include "XPM.h"
62 
63 #include "Scintilla.h"
64 #include "ScintillaWidget.h"
65 #ifdef SCI_LEXER
66 # include "SciLexer.h"
67 # include "ILexer.h"
68 # include "LexerModule.h"
69 # include "ExternalLexer.h"
70 #endif
71 #include "SplitVector.h"
72 #include "Partitioning.h"
73 #include "RunStyles.h"
74 #include "ContractionState.h"
75 #include "CellBuffer.h"
76 #include "CallTip.h"
77 #include "KeyMap.h"
78 #include "Indicator.h"
79 #include "LineMarker.h"
80 #include "Style.h"
81 #include "AutoComplete.h"
82 #include "ViewStyle.h"
83 #include "CharClassify.h"
84 #include "Decoration.h"
85 #include "CaseFolder.h"
86 #include "Document.h"
87 #include "Selection.h"
88 #include "PositionCache.h"
89 #include "Editor.h"
90 #include "ScintillaBase.h"
91 
92 #ifdef WIN32
93 #ifdef FOXDLL
94 #undef FXAPI
95 #define FXAPI __declspec(dllexport)
96 #endif
97 #endif
98 #include "FXScintilla.h"
99 
100 #ifdef _MSC_VER
101 // Constant conditional expressions are because of GTK+ headers
102 #pragma warning(disable: 4127)
103 #endif
104 
105 #include <FX88591Codec.h>
106 
107 #include "version.h"
108 
109 // ====================================================================
110 // ScintillaFOX
111 // ====================================================================
112 class ScintillaFOX : public ScintillaBase {
113   friend class FXScintilla;
114 protected:
115   FXScintilla & _fxsc;
116   bool tryDrag;
117   bool dragWasDropped;
118   Point ptMouseLastBeforeDND;
119 
120   // Because clipboard access is asynchronous, copyText is created by Copy
121   SelectionText copyText;
122   SelectionText primary;
123 
124   // Vertical scrollbar handling
125   int vsbMax;
126   int vsbPage;
127 
128   // Flag to prevent infinite loop with moveContents
129   bool inMoveContents;
130 public:
131   ScintillaFOX(FXScintilla & fxsc);
132   virtual ~ScintillaFOX();
133   virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
134 private:
135   int TargetAsUTF8(char *text);
136   int EncodedFromUTF8(char *utf8, char *encoded);
137   // Virtual methods from ScintillaBase
138   virtual void Initialise();
139   virtual void Finalise();
140   virtual void DisplayCursor(Window::Cursor c);
141   virtual void SetVerticalScrollPos();
142   virtual void SetHorizontalScrollPos();
143   virtual void CopyToClipboard(const SelectionText &selectedText);
144   virtual void Copy();
145   virtual void Paste();
146   virtual void ClaimSelection();
147   virtual void NotifyChange();
148   virtual void NotifyParent(SCNotification scn);
149   virtual void SetTicking(bool on);
150   virtual bool SetIdle(bool on);
151   virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo);
152   virtual void SetMouseCapture(bool on);
153   virtual bool HaveMouseCapture();
154   virtual bool PaintContains(PRectangle rc);
155   virtual sptr_t DefWndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam);
156   virtual void CreateCallTipWindow(PRectangle rc);
157   virtual void AddToPopUp(const char * label, int cmd = 0, bool enabled = true);
158   virtual void StartDrag();
159   virtual bool ValidCodePage(int codePage) const;
160   //
161   static sptr_t DirectFunction(ScintillaFOX *sciThis,
162     unsigned int iMessage, uptr_t wParam, sptr_t lParam);
163   // Paint
164   void SyncPaint(PRectangle rc);
165   void FullPaint();
166   void UnclaimSelection();
167   void ReceivedSelection(FXDNDOrigin origin, int atPos);
168   void NotifyKey(int key, int modifiers);
169   void NotifyURIDropped(const char *list);
170 
171   // From ScintillaBase
172   virtual bool ModifyScrollBars(int nMax, int nPage);
173   virtual void ReconfigureScrollBars();
174   virtual PRectangle GetClientRectangle() const;
175   virtual int KeyDefault(int key, int modifiers);
176 
177   // Popup flag
getDisplayPopupMenu() const178   bool getDisplayPopupMenu() const { return displayPopupMenu; }
179 };
180 
ScintillaFOX(FXScintilla & fxsc)181 ScintillaFOX::ScintillaFOX(FXScintilla & fxsc) :
182   _fxsc(fxsc),
183   tryDrag(false),
184   dragWasDropped(false),
185   vsbMax(0),
186   vsbPage(0),
187   inMoveContents(false)
188 {
189   wMain = &_fxsc;
190   Initialise();
191 }
192 
~ScintillaFOX()193 ScintillaFOX::~ScintillaFOX()
194 {
195   Finalise();
196 }
197 
TargetAsUTF8(char * text)198 int ScintillaFOX::TargetAsUTF8(char *text) {
199   (void)text;
200   // TODO
201   // Fail
202   return 0;
203 }
204 
EncodedFromUTF8(char * utf8,char * encoded)205 int ScintillaFOX::EncodedFromUTF8(char *utf8, char *encoded) {
206   (void)utf8;
207   (void)encoded;
208   // TODO
209   // Fail
210   return 0;
211 }
212 
ValidCodePage(int codePage) const213 bool ScintillaFOX::ValidCodePage(int codePage) const {
214   return codePage == 0
215   || codePage == SC_CP_UTF8
216   || codePage == 932
217   || codePage == 936
218   || codePage == 949
219   || codePage == 950
220   || codePage == 1361;
221 }
222 
WndProc(unsigned int iMessage,uptr_t wParam,sptr_t lParam)223 sptr_t ScintillaFOX::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
224   switch (iMessage) {
225 
226   case SCI_GRABFOCUS:
227     _fxsc.setFocus();
228     break;
229 
230   case SCI_GETDIRECTFUNCTION:
231     return reinterpret_cast<sptr_t>(DirectFunction);
232 
233   case SCI_GETDIRECTPOINTER:
234     return reinterpret_cast<sptr_t>(this);
235 
236 #ifdef SCI_LEXER
237   case SCI_LOADLEXERLIBRARY:
238     LexerManager::GetInstance()->Load(reinterpret_cast<const char*>(wParam));
239     break;
240 #endif
241   case SCI_TARGETASUTF8:
242     return TargetAsUTF8(reinterpret_cast<char*>(lParam));
243 
244   case SCI_ENCODEDFROMUTF8:
245     return EncodedFromUTF8(reinterpret_cast<char*>(wParam),
246       reinterpret_cast<char*>(lParam));
247 
248   default:
249     return ScintillaBase::WndProc(iMessage,wParam,lParam);
250   }
251   return 0l;
252 }
253 
ClaimSelection()254 void ScintillaFOX::ClaimSelection()
255 {
256   // Acquire selection
257 
258 // JKP  1.79 if (currentPos != anchor) {
259 // JKP 2.00 ? if (SelectionStart().Position() != SelectionEnd().Position()) {
260   if (!sel.Empty()) { // <- JKP 2.00
261     _fxsc.acquireSelection(&FXWindow::stringType,1);
262     primarySelection = true;
263     primary.Clear();
264   }
265   else {
266 //  _fxsc.releaseSelection(); // JKP:  Does not work for 2.00 - Do we need somethong else?
267   }
268 }
269 
UnclaimSelection()270 void ScintillaFOX::UnclaimSelection()
271 {
272   //Platform::DebugPrintf("UnclaimPrimarySelection\n");
273   if (!_fxsc.hasSelection()) {
274     primary.Clear();
275     primarySelection = false;
276     FullPaint();
277   }
278 }
279 
280 #ifdef WIN32
cfColumnSelect()281 static CLIPFORMAT cfColumnSelect()
282 {
283   static CLIPFORMAT cf = static_cast<CLIPFORMAT>(::RegisterClipboardFormat("MSDEVColumnSelect"));
284   return cf;
285 }
286 #endif
287 
288 #define InUTF8Mode(sf) (sf->CodePage()==SC_CP_UTF8)
289 
290 // JKP: Heavily reworked to fix middle-click-paste when current document has the X-selection.
291 // JKP: Still more reworking for 2.00!
ReceivedSelection(FXDNDOrigin origin,int atPos)292 void ScintillaFOX::ReceivedSelection(FXDNDOrigin origin, int atPos)
293 {
294   FXuchar *data=NULL;
295   FXuint len=0;
296   if (pdoc->IsReadOnly()) { return; }
297   if (InUTF8Mode(this)&&_fxsc.getDNDData(origin, FXWindow::utf8Type, data, len)) {
298     /* If the data and the scintilla are both UTF-8, then no conversion is needed. */
299   } else {
300     if(_fxsc.getDNDData(origin, FXWindow::stringType, data, len)) {
301       if (InUTF8Mode(this)) {
302         for (FXuint i=0; i<len; i++) {
303           if ((FXuchar)(data[i])>126) { // We are in UTF-8 mode, but the data is extended ASCII
304             FX88591Codec asciiCodec;
305             FXString codecBuffer;
306             codecBuffer.length(asciiCodec.mb2utflen((FXchar*)data,len));
307             asciiCodec.mb2utf(&(codecBuffer.at(0)),codecBuffer.length(),(FXchar*)data,len);
308             FXRESIZE(&data,FXuchar,codecBuffer.length());
309             memcpy(data, codecBuffer.text(),codecBuffer.length());
310             len=codecBuffer.length();
311             break;
312           }
313         }
314       }
315     } else { // Type of DND data must be something we don't know how to deal with.
316       return;
317     }
318   }
319   FXRESIZE(&data,FXuchar,len+1);
320   data[len]='\0';
321   bool isRectangular;
322   SelectionText selText;
323 
324 #ifdef WIN32
325   len=0;
326   while(data[len]) { len++; }
327   isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect()) != 0;
328 #else // !WIN32
329   isRectangular = ((len > 2) && (data[len - 1] == 0 && data[len - 2] == '\n'));
330 #endif // WIN32
331 
332   std::string dest = Document::TransformLineEnds((char*)data, len, pdoc->eolMode);
333   selText.Copy(dest.c_str(), CodePage(), 0, isRectangular, false);
334   pdoc->BeginUndoAction();
335 
336   if(_fxsc.hasSelection() && (origin == FROM_CLIPBOARD)) { ClearSelection(); }
337 
338   SelectionPosition selStart = sel.IsRectangular() ?
339 	  sel.Rectangular().Start() :
340 	  sel.Range(sel.Main()).Start();
341 
342   if (selText.rectangular) {
343     PasteRectangular(selStart, selText.Data(), selText.Length());
344   } else {
345     if (atPos<0) {
346       selStart = SelectionPosition(InsertSpace(selStart.Position(), selStart.VirtualSpace()));
347       if (pdoc->InsertString(selStart.Position(),selText.Data(), selText.Length())) {
348         SetEmptySelection( (selStart.Position()) + selText.Length() );
349       }
350     } else {
351       if (pdoc->InsertString(atPos,selText.Data(), selText.Length())) {
352         SetEmptySelection(atPos+selText.Length());
353         FullPaint();
354       }
355     }
356   }
357   pdoc->EndUndoAction();
358   EnsureCaretVisible();
359 //  _fxsc.setDNDData(origin, FXWindow::stringType, data, len);
360   FXFREE(&data);
361 }
362 
363 
NotifyKey(int key,int modifiers)364 void ScintillaFOX::NotifyKey(int key, int modifiers) {
365   SCNotification scn;
366   scn.nmhdr.code = SCN_KEY;
367   scn.ch = key;
368   scn.modifiers = modifiers;
369 
370   NotifyParent(scn);
371 }
372 
NotifyURIDropped(const char * list)373 void ScintillaFOX::NotifyURIDropped(const char *list) {
374   SCNotification scn;
375   scn.nmhdr.code = SCN_URIDROPPED;
376   scn.text = list;
377 
378   NotifyParent(scn);
379 }
380 
KeyDefault(int key,int modifiers)381 int ScintillaFOX::KeyDefault(int key, int modifiers) {
382   if (!(modifiers & SCI_CTRL) && !(modifiers & SCI_ALT) && (key < 256)) {
383     //NotifyKey(key, modifiers);
384     //return 0;
385     AddChar(key);
386     return 1;
387   } else {
388     // Pass up to container in case it is an accelerator
389     NotifyKey(key, modifiers);
390     return 0;
391   }
392   //Platform::DebugPrintf("SK-key: %d %x %x\n",key, modifiers);
393 }
394 
395 // ********************************************************************
396 
Initialise()397 void ScintillaFOX::Initialise()
398 {
399   SetTicking(true);
400 }
401 
Finalise()402 void ScintillaFOX::Finalise()
403 {
404   SetTicking(false);
405   ScintillaBase::Finalise();
406 }
407 
DisplayCursor(Window::Cursor c)408 void ScintillaFOX::DisplayCursor(Window::Cursor c) {
409   if (cursorMode == SC_CURSORNORMAL)
410     wMain.SetCursor(c);
411   else
412     wMain.SetCursor(static_cast<Window::Cursor>(cursorMode));
413 }
414 
SetVerticalScrollPos()415 void ScintillaFOX::SetVerticalScrollPos()
416 {
417   if (inMoveContents) return;
418   // Update the scrollbar position only if this method is not called by
419   // moveContents (to prevent an infinite loop becaude setPosition
420   // triggers moveContents).
421   // BTW scrollbar should be up to date when in movecontents.
422   DwellEnd(true);
423 #ifdef FOX_1_6
424     _fxsc.setPosition(_fxsc.getXPosition(), -topLine * vs.lineHeight);
425 #else
426     FXint gpx,gpy;
427     _fxsc.getPosition(gpx,gpy);
428     _fxsc.setPosition(gpx, -topLine * vs.lineHeight);
429 #endif
430 }
431 
SetHorizontalScrollPos()432 void ScintillaFOX::SetHorizontalScrollPos()
433 {
434   if (inMoveContents) return;
435   // Update the scrollbar position only if this method is not called by
436   // moveContents (to prevent an infinite loop becaude setPosition
437   // triggers moveContents).
438   // BTW scrollbar should be up to date when in movecontents.
439   DwellEnd(true);
440 #ifdef FOX_1_6
441   _fxsc.setPosition(-xOffset, _fxsc.getYPosition());
442 #else
443   FXint gpx,gpy;
444   _fxsc.getPosition(gpx,gpy);
445   _fxsc.setPosition(-xOffset, gpy);
446 #endif
447 }
448 
CopyToClipboard(const SelectionText & selectedText)449 void ScintillaFOX::CopyToClipboard(const SelectionText &selectedText) {
450   if (_fxsc.acquireClipboard(&FXWindow::stringType, 1)) {
451     copyText.Copy(selectedText);
452   }
453 }
454 
455 #ifdef WIN32
Copy()456 void ScintillaFOX::Copy()
457 {
458   if (_fxsc.hasSelection()) {
459     FXDragType dt[2] = {
460       FXWindow::stringType,
461       sel.selType==Selection::selRectangle ? cfColumnSelect() : (FXDragType)0
462     };
463     if (_fxsc.acquireClipboard(dt, dt[1]?2:1)) {
464       CopySelectionRange(&copyText);
465     }
466   } else {
467     _fxsc.releaseClipboard();
468   }
469 }
470 #else
Copy()471 void ScintillaFOX::Copy()
472 {
473   if (_fxsc.hasSelection()) {
474     if (_fxsc.acquireClipboard(&FXWindow::stringType, 1)) {
475       CopySelectionRange(&copyText);
476     }
477   }
478   else {
479     _fxsc.releaseClipboard();
480   }
481 }
482 #endif
483 
Paste()484 void ScintillaFOX::Paste()
485 {
486   ReceivedSelection(FROM_CLIPBOARD, -1);
487 }
488 
NotifyChange()489 void ScintillaFOX::NotifyChange()
490 {
491   _fxsc.handle(&_fxsc, MKUINT(0, SEL_CHANGED), NULL);
492 }
493 
NotifyParent(SCNotification scn)494 void ScintillaFOX::NotifyParent(SCNotification scn)
495 {
496   scn.nmhdr.hwndFrom = wMain.GetID();
497   scn.nmhdr.idFrom = GetCtrlID();
498   _fxsc.handle(&_fxsc, MKUINT(0, SEL_COMMAND), &scn);
499 }
500 
SetTicking(bool on)501 void ScintillaFOX::SetTicking(bool on)
502 {
503   if (timer.ticking != on) {
504     timer.ticking = on;
505     if (timer.ticking) {
506       FXApp::instance()->addTimeout(&_fxsc, _fxsc.ID_TICK, timer.tickSize);
507     } else {
508       FXApp::instance()->removeTimeout(&_fxsc, _fxsc.ID_TICK);
509     }
510   }
511   timer.ticksToWait = caret.period;
512 }
513 
SetIdle(bool on)514 bool ScintillaFOX::SetIdle(bool on) {
515   if (on) {
516     // Start idler, if it's not running.
517     if (idler.state == false) {
518       idler.state = true;
519       FXApp::instance()->addChore(&_fxsc, FXScintilla::ID_IDLE);
520     }
521   } else {
522     // Stop idler, if it's running
523     if (idler.state == true) {
524       idler.state = false;
525       FXApp::instance()->removeChore(&_fxsc, FXScintilla::ID_IDLE);
526     }
527   }
528   return true;
529 }
530 
QueueIdleWork(WorkNeeded::workItems items,int upTo)531 void ScintillaFOX::QueueIdleWork(WorkNeeded::workItems items, int upTo) {
532   Editor::QueueIdleWork(items, upTo);
533   if (!workNeeded.active) {
534     // Only allow one style needed to be queued
535     workNeeded.active = true;
536     FXApp::instance()->addChore(&_fxsc, FXScintilla::ID_STYLE_IDLE);
537   }
538 }
539 
SetMouseCapture(bool on)540 void ScintillaFOX::SetMouseCapture(bool on)
541 {
542   if (mouseDownCaptures) {
543     if (on) {
544       _fxsc.grab();
545     } else {
546       _fxsc.ungrab();
547     }
548   }
549 }
550 
HaveMouseCapture()551 bool ScintillaFOX::HaveMouseCapture()
552 {
553   return _fxsc.grabbed();
554 }
555 
PaintContains(PRectangle rc)556 bool ScintillaFOX::PaintContains(PRectangle rc) {
557   bool contains = true;
558   if (paintState == painting) {
559     if (!rcPaint.Contains(rc)) {
560       contains = false;
561     }
562   }
563   return contains;
564 }
565 
StartDrag()566 void ScintillaFOX::StartDrag()
567 {
568   tryDrag = true;
569   dragWasDropped = false;
570 }
571 
DefWndProc(unsigned int,uptr_t,sptr_t)572 sptr_t ScintillaFOX::DefWndProc(unsigned int, uptr_t, sptr_t)
573 {
574   return 0;
575 }
576 
577 
578 // JKP: A new class, overrides the onPaint() method to
579 // let a CallTip object take over the painting.
580 class CallTipWindow:public FXFrame {
581   FXDECLARE(CallTipWindow)
CallTipWindow()582   CallTipWindow(){}
583 protected:
584   CallTip*ct;
585 public:
586   long onPaint(FXObject*o, FXSelector sel, void*p);
CallTipWindow(FXComposite * p,CallTip * _ct)587   CallTipWindow( FXComposite *p, CallTip*_ct):FXFrame(p,FRAME_NONE|LAYOUT_FILL),ct(_ct) {}
588 };
589 
590 FXDEFMAP(CallTipWindow) CallTipWindowMap[] = {
591   FXMAPFUNC(SEL_PAINT,0,CallTipWindow::onPaint)
592 };
593 
594 FXIMPLEMENT(CallTipWindow,FXFrame,CallTipWindowMap,ARRAYNUMBER(CallTipWindowMap));
595 
onPaint(FXObject * o,FXSelector sel,void * p)596 long CallTipWindow::onPaint(FXObject*o, FXSelector sel, void*p)
597 {
598   long rv=FXFrame::onPaint(o,sel,p);
599   Surface *surfaceWindow = Surface::Allocate(SC_TECHNOLOGY_DEFAULT);
600   if (surfaceWindow) {
601     surfaceWindow->Init(this, this);
602     surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ct->codePage);
603     surfaceWindow->SetDBCSMode(ct->codePage);
604     ct->PaintCT(surfaceWindow);
605     surfaceWindow->Release();
606     delete surfaceWindow;
607   }
608   return rv;
609 }
610 
611 
CreateCallTipWindow(PRectangle rc)612 void ScintillaFOX::CreateCallTipWindow(PRectangle  rc )
613 {
614   // Gilles says: <FIXME/>
615   // JKP says: OK, I'll try....
616   if (!ct.wCallTip.GetID()) {
617     FXHorizontalFrame*w=new FXHorizontalFrame(&_fxsc,FRAME_NONE,rc.left, rc.top,
618       (rc.right-rc.left), (rc.bottom-rc.top),0,0,0,0,0,0);
619     CallTipWindow*c=new CallTipWindow(w, &ct);
620     w->create();
621     ct.wCallTip=w;
622     ct.wDraw=c;
623   }
624 }
625 
626 
627 
628 class PopUpCmd: public FXMenuCommand {
629   FXDECLARE(PopUpCmd)
PopUpCmd()630   PopUpCmd() {}
631   protected:
632 #ifdef FOX_1_6
633  FXlong CreationTime;
634 #else
635  FXTime CreationTime;
636 #endif
637 public:
PopUpCmd(FXComposite * p,const FXString & text,FXIcon * ic,FXObject * tgt,FXSelector sel)638   PopUpCmd(FXComposite* p,const FXString& text,FXIcon* ic,FXObject* tgt,FXSelector sel):
639      FXMenuCommand(p,text,ic,tgt,sel), CreationTime(FXThread::time()) { }
onButtonRelease(FXObject * o,FXSelector sel,void * p)640   long onButtonRelease(FXObject*o,FXSelector sel,void*p) {
641     return (FXThread::time()-CreationTime)<500000000 ? 1 : FXMenuCommand::onButtonRelease(o,sel,p);
642   }
643 };
644 FXDEFMAP(PopUpCmd) PopUpCmdMap[]={ FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,0,PopUpCmd::onButtonRelease) };
645 FXIMPLEMENT(PopUpCmd,FXMenuCommand,PopUpCmdMap,ARRAYNUMBER(PopUpCmdMap));
646 
647 
648 
AddToPopUp(const char * label,int cmd,bool enabled)649 void ScintillaFOX::AddToPopUp(const char * label, int cmd, bool enabled)
650 {
651   if (label[0]) {
652     PopUpCmd* item = new PopUpCmd(static_cast<FXComposite *>(popup.GetID()), label, NULL, &_fxsc, SCID(cmd));
653     if (!enabled)
654       item->disable();
655   }
656   else
657     new FXMenuSeparator(static_cast<FXComposite *>(popup.GetID()));
658 }
659 
DirectFunction(ScintillaFOX * sciThis,unsigned int iMessage,uptr_t wParam,sptr_t lParam)660 sptr_t ScintillaFOX::DirectFunction(
661     ScintillaFOX *sciThis, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
662   return sciThis->WndProc(iMessage, wParam, lParam);
663 }
664 
GetClientRectangle() const665 PRectangle ScintillaFOX::GetClientRectangle() const {
666   // Have to call FXScrollArea::getViewportXxxx instead of getViewportXxxx
667   // to prevent infinite loop
668 #ifdef FOX_1_6
669   PRectangle rc(0, 0, _fxsc.FXScrollArea::getViewportWidth(), _fxsc.FXScrollArea::getViewportHeight());
670   if (_fxsc.horizontalScrollBar()->shown())
671     rc.bottom -= _fxsc.horizontalScrollBar()->getDefaultHeight();
672   if (_fxsc.verticalScrollBar()->shown())
673     rc.right -= _fxsc.verticalScrollBar()->getDefaultWidth();
674 #else
675   PRectangle rc(0, 0, _fxsc.FXScrollArea::getVisibleWidth(), _fxsc.FXScrollArea::getVisibleHeight());
676 #endif
677   return rc;
678 }
679 
ReconfigureScrollBars()680 void ScintillaFOX::ReconfigureScrollBars()
681 {
682   if (horizontalScrollBarVisible)
683     _fxsc.setScrollStyle(_fxsc.getScrollStyle() & ~HSCROLLER_NEVER);
684   else
685     _fxsc.setScrollStyle(_fxsc.getScrollStyle() | HSCROLLER_NEVER);
686   _fxsc.recalc();
687 }
688 
ModifyScrollBars(int nMax,int nPage)689 bool ScintillaFOX::ModifyScrollBars(int nMax, int nPage)
690 {
691   bool modified = false;
692   // There was no vertical scrollbar if
693   //   !vsbMax || (vsbMax < vsbPage)
694   bool noVScroll = !vsbMax || (vsbMax < vsbPage);
695   // There won't be a vertical scrollbar if
696   //   !nMax || (nMax < nPage)
697   bool noVScrollNew = !nMax || (nMax < nPage);
698   if ((nMax != vsbMax) || (nPage != vsbPage)) {
699     vsbMax = nMax;
700     vsbPage = nPage;
701     // Layout if vertical scrollbar should appear or change
702     if (noVScroll != noVScrollNew || !noVScroll) {
703       _fxsc.layout();
704       if (noVScrollNew)
705         ChangeSize();  // Force scrollbar recalc
706       modified = true;
707     }
708   }
709   // Vertical scrollbar
710   int line = vs.lineHeight;
711   if (_fxsc.verticalScrollBar()->getLine() != line) {
712     _fxsc.verticalScrollBar()->setLine(line);
713     modified = true;
714   }
715   // Horizontal scrollbar
716   PRectangle rcText = GetTextRectangle();
717   unsigned int pageWidth = rcText.Width();
718   if ((_fxsc.horizontalScrollBar()->getPage() != int(pageWidth)) ||
719       (_fxsc.horizontalScrollBar()->getLine() != 10)) {
720     _fxsc.horizontalScrollBar()->setPage(pageWidth);
721     _fxsc.horizontalScrollBar()->setLine(10);
722     modified = true;
723   }
724   return modified;
725 }
726 
727 // --------------------------------------------------------------------
728 // Synchronously paint a rectangle of the window.
SyncPaint(PRectangle rc)729 void ScintillaFOX::SyncPaint(PRectangle rc) {
730   paintState = painting;
731   rcPaint = rc;
732   PRectangle rcClient = GetClientRectangle();
733   paintingAllText = rcPaint.Contains(rcClient);
734   //Platform::DebugPrintf("ScintillaGTK::SyncPaint %0d,%0d %0d,%0d\n",
735   //  rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
736   Surface *sw = Surface::Allocate(SC_TECHNOLOGY_DEFAULT);
737   if (sw) {
738     sw->Init(wMain.GetID(), wMain.GetID());
739     Paint(sw, rcPaint);
740     sw->Release();
741     delete sw;
742   }
743   if (paintState == paintAbandoned) {
744     // Painting area was insufficient to cover new styling or brace highlight positions
745     FullPaint();
746   }
747   paintState = notPainting;
748 }
749 
750 // Redraw all of text area. This paint will not be abandoned.
FullPaint()751 void ScintillaFOX::FullPaint() {
752   paintState = painting;
753   rcPaint = GetClientRectangle();
754   //Platform::DebugPrintf("ScintillaGTK::FullPaint %0d,%0d %0d,%0d\n",
755   //  rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
756   paintingAllText = true;
757   if (wMain.GetID()) {
758     Surface *sw = Surface::Allocate(SC_TECHNOLOGY_DEFAULT);
759     if (sw) {
760       sw->Init(wMain.GetID(), wMain.GetID());
761       Paint(sw, rcPaint);
762       sw->Release();
763       delete sw;
764     }
765   }
766   paintState = notPainting;
767 }
768 
769 // ====================================================================
SendScintilla(WindowID w,unsigned int msg,unsigned long wParam,long lParam)770 long Platform::SendScintilla(
771     WindowID w, unsigned int msg, unsigned long wParam, long lParam) {
772   return static_cast<FXScintilla *>(w)->sendMessage(msg, wParam, lParam);
773 }
774 
SendScintillaPointer(WindowID w,unsigned int msg,unsigned long wParam,void * lParam)775 long Platform::SendScintillaPointer(WindowID w, unsigned int msg,
776                                     unsigned long wParam, void *lParam) {
777   return static_cast<FXScintilla *>(w)->
778     sendMessage(msg, wParam, reinterpret_cast<sptr_t>(lParam));
779 }
780 
781 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
782 // FXScintilla
783 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
784 
785 FXDEFMAP(FXScintilla) FXScintillaMap[]={
786   FXMAPFUNCS(SEL_COMMAND, FXScrollArea::ID_LAST, FXScintilla::idLast, FXScintilla::onScintillaCommand),
787   FXMAPFUNC(SEL_COMMAND, 0, FXScintilla::onCommand),
788   FXMAPFUNC(SEL_CHANGED, 0, FXScintilla::onChanged),
789   FXMAPFUNC(SEL_PAINT, 0, FXScintilla::onPaint),
790   FXMAPFUNC(SEL_CONFIGURE,0,FXScintilla::onConfigure),
791   FXMAPFUNC(SEL_TIMEOUT,FXScintilla::ID_TICK,FXScintilla::onTimeoutTicking),
792   FXMAPFUNC(SEL_FOCUSIN,0,FXScintilla::onFocusIn),
793   FXMAPFUNC(SEL_FOCUSOUT,0,FXScintilla::onFocusOut),
794   FXMAPFUNC(SEL_MOTION,0,FXScintilla::onMotion),
795   FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXScintilla::onLeftBtnPress),
796   FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXScintilla::onLeftBtnRelease),
797   FXMAPFUNC(SEL_RIGHTBUTTONPRESS,0,FXScintilla::onRightBtnPress),
798   FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,FXScintilla::onMiddleBtnPress),
799   FXMAPFUNC(SEL_BEGINDRAG,0,FXScintilla::onBeginDrag),
800   FXMAPFUNC(SEL_DRAGGED,0,FXScintilla::onDragged),
801   FXMAPFUNC(SEL_ENDDRAG,0,FXScintilla::onEndDrag),
802   FXMAPFUNC(SEL_DND_ENTER,0,FXScintilla::onDNDEnter),
803   FXMAPFUNC(SEL_DND_LEAVE,0,FXScintilla::onDNDLeave),
804   FXMAPFUNC(SEL_DND_DROP,0,FXScintilla::onDNDDrop),
805   FXMAPFUNC(SEL_DND_MOTION,0,FXScintilla::onDNDMotion),
806   FXMAPFUNC(SEL_DND_REQUEST,0,FXScintilla::onDNDRequest),
807   FXMAPFUNC(SEL_SELECTION_LOST,0,FXScintilla::onSelectionLost),
808   FXMAPFUNC(SEL_SELECTION_GAINED,0,FXScintilla::onSelectionGained), // JKP
809   FXMAPFUNC(SEL_SELECTION_REQUEST,0,FXScintilla::onSelectionRequest),
810   FXMAPFUNC(SEL_CLIPBOARD_LOST,0,FXScintilla::onClipboardLost),
811   FXMAPFUNC(SEL_CLIPBOARD_GAINED,0,FXScintilla::onClipboardGained), // JKP
812   FXMAPFUNC(SEL_CLIPBOARD_REQUEST,0,FXScintilla::onClipboardRequest),
813   FXMAPFUNC(SEL_KEYPRESS,0,FXScintilla::onKeyPress),
814   FXMAPFUNC(SEL_CHORE,FXScintilla::ID_IDLE,FXScintilla::onChoreIdle),
815   FXMAPFUNC(SEL_CHORE,FXScintilla::ID_STYLE_IDLE,FXScintilla::onChoreStyleIdle),
816 };
817 
FXIMPLEMENT(FXScintilla,FXScrollArea,FXScintillaMap,ARRAYNUMBER (FXScintillaMap))818 FXIMPLEMENT(FXScintilla,FXScrollArea,FXScintillaMap,ARRAYNUMBER(FXScintillaMap))
819 
820 FXScintilla::FXScintilla()
821 {
822 }
823 
FXScintilla(FXComposite * p,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h)824 FXScintilla::FXScintilla(FXComposite * p, FXObject * tgt, FXSelector sel,
825     FXuint opts, FXint x, FXint y, FXint w, FXint h) :
826   FXScrollArea(p, opts, x, y, w, h)
827 {
828   flags|=FLAG_ENABLED;
829   target = tgt;
830   message = sel;
831   _scint = new ScintillaFOX(*this);
832 }
833 
~FXScintilla()834 FXScintilla::~FXScintilla()
835 {
836   delete _scint;
837 }
838 
create()839 void FXScintilla::create()
840 {
841   FXScrollArea::create();
842   _scint->wMain.SetCursor(Window::cursorArrow);
843   if(!textType){textType=getApp()->registerDragType(textTypeName);}
844   if(!utf8Type){utf8Type=getApp()->registerDragType(utf8TypeName);}
845   if(!urilistType){urilistType=getApp()->registerDragType(urilistTypeName);}
846   dropEnable();
847   if(getApp()->hasInputMethod()){createComposeContext();}
848 }
849 
destroy()850 void FXScintilla::destroy()
851 {
852   if(getApp()->hasInputMethod()){destroyComposeContext();}
853   FXScrollArea::destroy();
854 }
855 
canFocus() const856 bool FXScintilla::canFocus() const
857 {
858   return true;
859 }
860 
onScintillaCommand(FXObject *,FXSelector sel,void *)861 long FXScintilla::onScintillaCommand(FXObject *, FXSelector sel, void *)
862 {
863   _scint->Command(FXSELID(sel)-SCID(0));
864   return 1;
865 }
866 
onCommand(FXObject *,FXSelector sel,void * ptr)867 long FXScintilla::onCommand(FXObject *, FXSelector sel, void * ptr)
868 {
869   if (target)
870     return target->handle(this, MKUINT(message, FXSELTYPE(sel)), ptr);
871   return 0;
872 }
873 
onChanged(FXObject *,FXSelector sel,void * ptr)874 long FXScintilla::onChanged(FXObject *, FXSelector sel, void * ptr)
875 {
876   if (target)
877     return target->handle(this, MKUINT(message, FXSELTYPE(sel)), ptr);
878   return 0;
879 }
880 
onPaint(FXObject *,FXSelector,void * ptr)881 long FXScintilla::onPaint(FXObject *, FXSelector, void * ptr)
882 {
883   FXEvent   *ev=(FXEvent*)ptr;
884   PRectangle rcPaint(ev->rect.x, ev->rect.y, ev->rect.x + ev->rect.w - 1, ev->rect.y + ev->rect.h - 1);
885   _scint->SyncPaint(rcPaint);
886   return 1;
887 }
888 
onTimeoutTicking(FXObject *,FXSelector,void *)889 long FXScintilla::onTimeoutTicking(FXObject *, FXSelector, void *)
890 {
891 #ifdef FOX_1_6
892   FXApp::instance()->addTimeout(this, ID_TICK, _scint->timer.tickSize);
893 #else
894   FXApp::instance()->addTimeout(this, ID_TICK, _scint->timer.tickSize*1000000);
895 #endif
896   _scint->Tick();
897   return 0;
898 }
899 
onChoreIdle(FXObject *,FXSelector,void *)900 long FXScintilla::onChoreIdle(FXObject *, FXSelector, void *)
901 {
902   // Idler will be automatically stoped, if there is nothing
903   // to do while idle.
904   bool ret = _scint->Idle();
905   if (ret == false) {
906     _scint->SetIdle(false);
907   } else {
908     FXApp::instance()->addChore(this, FXScintilla::ID_IDLE);
909   }
910   return 0;
911 }
912 
onChoreStyleIdle(FXObject *,FXSelector,void *)913 long FXScintilla::onChoreStyleIdle(FXObject *, FXSelector, void *)
914 {
915   // Idler will be automatically stopped
916   _scint->IdleWork();
917   return 1;
918 }
919 
onFocusIn(FXObject * sender,FXSelector sel,void * ptr)920 long FXScintilla::onFocusIn(FXObject * sender, FXSelector sel, void * ptr)
921 {
922   FXScrollArea::onFocusIn(sender, sel, ptr);
923   _scint->SetFocusState(true);
924   return 1;
925 }
926 
onFocusOut(FXObject * sender,FXSelector sel,void * ptr)927 long FXScintilla::onFocusOut(FXObject * sender, FXSelector sel, void * ptr)
928 {
929   FXScrollArea::onFocusOut(sender, sel, ptr);
930   _scint->SetFocusState(false);
931   return 1;
932 }
933 
onMotion(FXObject *,FXSelector,void * ptr)934 long FXScintilla::onMotion(FXObject *, FXSelector, void * ptr)
935 {
936   FXEvent * ev = static_cast<FXEvent *>(ptr);
937   if (_scint->tryDrag) {
938     _scint->tryDrag = false;
939     handle(this, MKUINT(0, SEL_BEGINDRAG), 0);
940   }
941   if (isDragging()) {
942     return handle(this, MKUINT(0, SEL_DRAGGED), ptr);
943   }
944   else {
945     Point pt(ev->win_x, ev->win_y);
946     _scint->ButtonMove(pt);
947   }
948   return 1;
949 }
950 
onLeftBtnPress(FXObject *,FXSelector,void * ptr)951 long FXScintilla::onLeftBtnPress(FXObject *, FXSelector, void * ptr)
952 {
953 //  if (FXScrollArea::onLeftBtnPress(sender, sel, ptr))
954 //    return 1;
955   handle(this, MKUINT(0, SEL_FOCUS_SELF), ptr);
956   setFocus();
957   FXEvent * ev = static_cast<FXEvent *>(ptr);
958   Point pt;
959   pt.x = ev->win_x;
960   pt.y = ev->win_y;
961     //sciThis->ButtonDown(pt, event->time,
962     //  event->state & GDK_SHIFT_MASK,
963     //  event->state & GDK_CONTROL_MASK,
964     //  event->state & GDK_MOD1_MASK);
965     // Instead of sending literal modifiers use control instead of alt
966     // This is because all the window managers seem to grab alt + click for moving
967   _scint->ButtonDown(pt, ev->time,
968       ev->state & SHIFTMASK,
969       ev->state & CONTROLMASK,
970       ev->state & CONTROLMASK);
971   return 1;
972 }
973 
onLeftBtnRelease(FXObject *,FXSelector,void * ptr)974 long FXScintilla::onLeftBtnRelease(FXObject *, FXSelector, void * ptr)
975 {
976   if (isDragging())
977     return handle(this, MKUINT(0, SEL_ENDDRAG), ptr);
978   FXEvent * ev = static_cast<FXEvent *>(ptr);
979   Point pt(ev->win_x, ev->win_y);
980   if (!_scint->HaveMouseCapture()) {
981     if (_scint->tryDrag) {
982       _scint->tryDrag = false;
983       _scint->SetEmptySelection(_scint->PositionFromLocation(pt));
984       _scint->SetDragPosition(SelectionPosition(invalidPosition));
985     }
986     return 1;
987   }
988   _scint->ButtonUp(pt, ev->time, (ev->state & CONTROLMASK) != 0);
989   return 1;
990 }
991 
onRightBtnPress(FXObject *,FXSelector sel,void * ptr)992 long FXScintilla::onRightBtnPress(FXObject *, FXSelector sel, void * ptr)
993 {
994 //  if (FXScrollArea::onRightBtnPress(sender, sel, ptr))
995 //    return 1;
996   if (target && target->handle(this, MKUINT(message, FXSELTYPE(sel)), ptr))
997     return 1;
998   if (!_scint->getDisplayPopupMenu())
999     return 0;
1000   FXEvent * ev = static_cast<FXEvent *>(ptr);
1001   _scint->ContextMenu(Point(ev->root_x, ev->root_y));
1002   return 1;
1003 }
1004 
onMiddleBtnPress(FXObject *,FXSelector,void * ptr)1005 long FXScintilla::onMiddleBtnPress(FXObject *, FXSelector, void * ptr)
1006 {
1007 //  if (FXScrollArea::onMiddleBtnPress(sender, sel, ptr))
1008 //    return 1;
1009   int pos;
1010   Point pt;
1011   pt.x = ((FXEvent *)ptr)->win_x;
1012   pt.y = ((FXEvent *)ptr)->win_y;
1013   pos=_scint->PositionFromLocation(pt);
1014   _scint->ReceivedSelection(FROM_SELECTION, pos);
1015 //  _scint->currentPos = pos; // JKP: Delay asignment of currentPos until AFTER ReceivedSelection()
1016 //  _scint->anchor = pos; // JKP
1017   return 1;
1018 }
1019 
1020 // ********************************************************************
1021 // Keyboard
1022 // ********************************************************************
1023 
1024 // Map the keypad keys to their equivalent functions
KeyTranslate(int keyIn)1025 static int KeyTranslate(int keyIn) {
1026   switch (keyIn) {
1027     case KEY_ISO_Left_Tab:
1028       return SCK_TAB;
1029     case KEY_KP_Down:
1030       return SCK_DOWN;
1031     case KEY_KP_Up:
1032       return SCK_UP;
1033     case KEY_KP_Left:
1034       return SCK_LEFT;
1035     case KEY_KP_Right:
1036       return SCK_RIGHT;
1037     case KEY_KP_Home:
1038       return SCK_HOME;
1039     case KEY_KP_End:
1040       return SCK_END;
1041     case KEY_KP_Page_Up:
1042       return SCK_PRIOR;
1043     case KEY_KP_Page_Down:
1044       return SCK_NEXT;
1045     case KEY_KP_Delete:
1046       return SCK_DELETE;
1047     case KEY_KP_Insert:
1048       return SCK_INSERT;
1049     case KEY_KP_Enter:
1050       return SCK_RETURN;
1051 
1052     case KEY_Down:
1053       return SCK_DOWN;
1054     case KEY_Up:
1055       return SCK_UP;
1056     case KEY_Left:
1057       return SCK_LEFT;
1058     case KEY_Right:
1059       return SCK_RIGHT;
1060     case KEY_Home:
1061       return SCK_HOME;
1062     case KEY_End:
1063       return SCK_END;
1064     case KEY_Page_Up:
1065       return SCK_PRIOR;
1066     case KEY_Page_Down:
1067       return SCK_NEXT;
1068     case KEY_Delete:
1069       return SCK_DELETE;
1070     case KEY_Insert:
1071       return SCK_INSERT;
1072     case KEY_Escape:
1073       return SCK_ESCAPE;
1074     case KEY_BackSpace:
1075       return SCK_BACK;
1076     case KEY_Tab:
1077       return SCK_TAB;
1078     case KEY_Return:
1079       return SCK_RETURN;
1080     case KEY_KP_Add:
1081       return SCK_ADD;
1082     case KEY_KP_Subtract:
1083       return SCK_SUBTRACT;
1084     case KEY_KP_Divide:
1085       return SCK_DIVIDE;
1086     default:
1087       return keyIn;
1088   }
1089 }
1090 
onKeyPress(FXObject * sender,FXSelector sel,void * ptr)1091 long FXScintilla::onKeyPress(FXObject* sender,FXSelector sel,void* ptr)
1092 {
1093   // Try handling it in base class first
1094   if (FXScrollArea::onKeyPress(sender,sel,ptr)) return 1;
1095 
1096   FXEvent *event=(FXEvent*)ptr;
1097   bool shift = (event->state & SHIFTMASK) != 0;
1098   bool ctrl = (event->state & CONTROLMASK) != 0;
1099   bool alt = (event->state & ALTMASK) != 0;
1100   FXint len = event->text.length();
1101   // Check for multi-byte UTF-8 character
1102   if ((_scint->pdoc->dbcsCodePage==SC_CP_UTF8)&&(len>1)&&(len<5) && !(ctrl||alt)) {
1103     if (_scint->pdoc->InsertCString(_scint->CurrentPosition(), (const char*)event->text.text())) {
1104       _scint->MovePositionTo(_scint->CurrentPosition() + len);
1105     }
1106     return 1;
1107   }
1108   // <FIXME> Workaround for event->code doesn't hold the correct
1109   // KEY_xxx under WIN32
1110 #ifndef WIN32
1111   int key = (event->code) ? event->code : event->text[0];
1112 #else
1113   if (!event->text[0] && (event->code < 256))
1114     return 0; // We did not handle it!
1115   int key = (((unsigned int)(event->text[0]) >= 32) && !ctrl && !alt) ?
1116     event->text[0] : event->code;
1117 #endif
1118   // </FIXME>
1119   if (ctrl && (key < 128))
1120     key = toupper(key);
1121   else if (!ctrl && (key >= KEY_KP_Multiply && key <= KEY_KP_9))
1122     key &= 0x7F;
1123   // Hack for keys over 256 and below command keys but makes Hungarian work.
1124   // This will have to change for Unicode
1125   else if ((key >= 0x100) && (key < 0x1000))
1126     key &= 0xff;
1127   else
1128     key = KeyTranslate(key);
1129 
1130   bool consumed = false;
1131   bool added = _scint->KeyDown(key, shift, ctrl, alt, &consumed) != 0;
1132   if (!consumed)
1133     consumed = added;
1134   //Platform::DebugPrintf("SK-key: %d %x %x\n",event->code, event->state, consumed);
1135   if (event->code == 0xffffff && event->text.length() > 0) {
1136     _scint->ClearSelection();
1137     if (_scint->pdoc->InsertCString(_scint->CurrentPosition(), (const char*)event->text.text())) {
1138       _scint->MovePositionTo(_scint->CurrentPosition() + event->text.length());
1139     }
1140     consumed = true;
1141   }
1142   return consumed ? 1 : 0;
1143 }
1144 
1145 // ********************************************************************
1146 // Clipboard
1147 // ********************************************************************
1148 
1149 // We lost the clipboard somehow
onClipboardLost(FXObject * sender,FXSelector sel,void * ptr)1150 long FXScintilla::onClipboardLost(FXObject* sender,FXSelector sel,void* ptr){
1151   FXScrollArea::onClipboardLost(sender,sel,ptr);
1152   //Platform::DebugPrintf("Clipboard lost\n");
1153   _scint->copyText.Clear();
1154 
1155   return 1;
1156 }
1157 
1158 // Somebody wants our clipboard
onClipboardRequest(FXObject * sender,FXSelector sel,void * ptr)1159 long FXScintilla::onClipboardRequest(FXObject* sender,FXSelector sel,void* ptr){
1160   FXEvent *event=(FXEvent*)ptr;
1161   FXuchar *cbdata;
1162   FXDragType types[]={utf8Type,stringType,0};
1163 
1164   // Try handling it in base class first
1165   if(FXScrollArea::onClipboardRequest(sender,sel,ptr)) return 1;
1166 
1167   for (FXDragType *dt=InUTF8Mode(_scint)?types:types+1; *dt; dt++) {
1168     if(event->target==*dt){
1169       // <FIXME> Framework taken from FXTextField.cpp - Should have a look to FXText.cpp too!
1170       size_t len=_scint->copyText.Length();
1171       FXCALLOC(&cbdata,FXuchar,len+1);
1172       memcpy(cbdata,_scint->copyText.Data(),len);
1173   #ifndef WIN32
1174       setDNDData(FROM_CLIPBOARD,*dt,cbdata,len);
1175   #else
1176       setDNDData(FROM_CLIPBOARD,*dt,cbdata,len+1);
1177   #endif
1178       // </FIXME>
1179       return 1;
1180     }
1181   }
1182   return 0;
1183 }
1184 
1185 // ********************************************************************
1186 // Drag'n drop
1187 // ********************************************************************
1188 
1189 // Start a drag operation
onBeginDrag(FXObject * sender,FXSelector sel,void * ptr)1190 long FXScintilla::onBeginDrag(FXObject* sender,FXSelector sel,void* ptr){
1191   _scint->SetMouseCapture(true);
1192   if (FXScrollArea::onBeginDrag(sender,sel,ptr)) return 1;
1193   beginDrag(&textType,1);
1194   setDragCursor(getApp()->getDefaultCursor(DEF_DNDSTOP_CURSOR));
1195   return 1;
1196 }
1197 
1198 
1199 // End drag operation
onEndDrag(FXObject * sender,FXSelector sel,void * ptr)1200 long FXScintilla::onEndDrag(FXObject* sender,FXSelector sel,void* ptr){
1201   _scint->inDragDrop = _scint->ddNone; // <-JKP: Fix for mouse not releasing.
1202   _scint->SetMouseCapture(false);
1203   if (FXScrollArea::onEndDrag(sender,sel,ptr)) return 1;
1204   endDrag((didAccept()!=DRAG_REJECT));
1205   setDragCursor(getApp()->getDefaultCursor(DEF_TEXT_CURSOR));
1206   _scint->SetDragPosition(SelectionPosition(invalidPosition));
1207   return 1;
1208 }
1209 
1210 
1211 // Dragged stuff around
onDragged(FXObject * sender,FXSelector sel,void * ptr)1212 long FXScintilla::onDragged(FXObject* sender,FXSelector sel,void* ptr) {
1213   FXEvent* event=(FXEvent*)ptr;
1214   FXDragAction action;
1215   if(FXScrollArea::onDragged(sender,sel,ptr)) return 1;
1216   action=DRAG_COPY;
1217   if (!_scint->pdoc->IsReadOnly()) {
1218     if (isDropTarget()) action=DRAG_MOVE;
1219     if (event->state&CONTROLMASK) action=DRAG_COPY;
1220     if (event->state&SHIFTMASK) action=DRAG_MOVE;
1221   }
1222   handleDrag(event->root_x,event->root_y,action);
1223 
1224   switch (didAccept()) {
1225     case DRAG_MOVE:
1226       setDragCursor(getApp()->getDefaultCursor(DEF_DNDMOVE_CURSOR));
1227       break;
1228     case DRAG_COPY:
1229       setDragCursor(getApp()->getDefaultCursor(DEF_DNDCOPY_CURSOR));
1230       break;
1231     default:
1232       setDragCursor(getApp()->getDefaultCursor(DEF_DNDSTOP_CURSOR));
1233       break;
1234   }
1235   return 1;
1236 }
1237 
1238 
1239 // Handle drag-and-drop enter
onDNDEnter(FXObject * sender,FXSelector sel,void * ptr)1240 long FXScintilla::onDNDEnter(FXObject* sender,FXSelector sel,void* ptr) {
1241   FXScrollArea::onDNDEnter(sender,sel,ptr);
1242   return 1;
1243 }
1244 
1245 
1246 // Handle drag-and-drop leave
onDNDLeave(FXObject * sender,FXSelector sel,void * ptr)1247 long FXScintilla::onDNDLeave(FXObject* sender,FXSelector sel,void* ptr) {
1248   stopAutoScroll();
1249   FXScrollArea::onDNDLeave(sender,sel,ptr);
1250   return 1;
1251 }
1252 
1253 // Handle drag-and-drop motion
onDNDMotion(FXObject * sender,FXSelector sel,void * ptr)1254 long FXScintilla::onDNDMotion(FXObject* sender,FXSelector sel,void* ptr){
1255   FXEvent* ev=(FXEvent*)ptr;
1256   FXDragAction action;
1257   FXint pos;
1258   // Scroll into view
1259   if(startAutoScroll(ev, true)) return 1;
1260 
1261   // Handled elsewhere
1262   if(FXScrollArea::onDNDMotion(sender,sel,ptr)) return 1;
1263 
1264   // Correct drop type
1265   if (offeredDNDType(FROM_DRAGNDROP,textType) ){
1266 
1267     // Is target editable?
1268     if (!_scint->pdoc->IsReadOnly()) {
1269       action=inquireDNDAction();
1270       // Check for legal DND action
1271       if (action==DRAG_COPY || action==DRAG_MOVE) {
1272         Point npt(ev->win_x, ev->win_y);
1273         pos = _scint->PositionFromLocation(npt);
1274         if (!_scint->inDragDrop) {
1275           _scint->inDragDrop = _scint->ddDragging; /*** or ddInitial ??? ***/
1276           _scint->ptMouseLastBeforeDND = _scint->ptMouseLast;
1277         }
1278         _scint->ptMouseLast = npt;
1279         _scint->SetDragPosition(SelectionPosition(pos));
1280 
1281         // JKP: Changed the logic here...
1282         if ( (!_scint->PositionInSelection(pos)) || (_scint->pdoc->Length()==0) ) {
1283           acceptDrop(DRAG_ACCEPT);
1284           setFocus();
1285         }
1286       }
1287     }
1288     return 1;
1289   }
1290 
1291   // Didn't handle it here
1292   return 0;
1293 }
1294 
1295 
1296 // Handle drag-and-drop drop
onDNDDrop(FXObject * sender,FXSelector sel,void * ptr)1297 long FXScintilla::onDNDDrop(FXObject* sender,FXSelector sel,void* ptr){
1298   FXuchar *dnddata,*junk;
1299   FXuint len,dum;
1300 
1301   // Stop scrolling
1302   stopAutoScroll();
1303 
1304   // Try handling it in base class first
1305   if(FXScrollArea::onDNDDrop(sender,sel,ptr)) return 1;
1306 
1307   // Should really not have gotten this if non-editable
1308   if (!_scint->pdoc->IsReadOnly()) {
1309 
1310     // Try handle here
1311     if(getDNDData(FROM_DRAGNDROP,textType,dnddata,len)){
1312       _scint->dragWasDropped = true;
1313       FXRESIZE(&dnddata,FXchar,len+1); dnddata[len]='\0';
1314 
1315       // Need to ask the source to delete his copy
1316       if(inquireDNDAction()==DRAG_MOVE){
1317         getDNDData(FROM_DRAGNDROP,deleteType,junk,dum);
1318         FXASSERT(!junk);
1319       }
1320 
1321       // Insert the new text
1322       bool isRectangular = ((len > 0) &&
1323           (dnddata[len] == 0 && dnddata[len-1] == '\n'));
1324       _scint->DropAt(_scint->posDrop, (const char *)(dnddata), false, isRectangular);
1325 
1326       FXFREE(&dnddata);
1327     }
1328     else if (getDNDData(FROM_DRAGNDROP,urilistType,dnddata,len)) {
1329       _scint->dragWasDropped = true;
1330       FXRESIZE(&dnddata,FXchar,len+1); dnddata[len]='\0';
1331       _scint->NotifyURIDropped((FXchar *)dnddata);
1332     }
1333     return 1;
1334   }
1335   return 0;
1336 }
1337 
1338 // Service requested DND data
onDNDRequest(FXObject * sender,FXSelector sel,void * ptr)1339 long FXScintilla::onDNDRequest(FXObject* sender,FXSelector sel,void* ptr) {
1340   FXEvent *event=(FXEvent*)ptr;
1341 
1342   // Perhaps the target wants to supply its own data
1343   if(FXScrollArea::onDNDRequest(sender,sel,ptr)) return 1;
1344 
1345   // Return dragged text
1346   if(event->target==textType){
1347     if (_scint->primary.Empty()) {
1348       _scint->CopySelectionRange(&_scint->primary);
1349 
1350     }
1351         if (!_scint->primary.Empty()) { /* JKP: This will crash if _scint->primary.s is NULL, so we test it first !!! */
1352           setDNDData(FROM_DRAGNDROP,stringType,(FXuchar *)strdup(_scint->primary.Data()),_scint->primary.Length());
1353         } else { setDNDData(FROM_DRAGNDROP,stringType,NULL,0); }
1354     return 1;
1355     }
1356 
1357   // Delete dragged text
1358   if(event->target==deleteType){
1359     if (!_scint->pdoc->IsReadOnly()) {
1360       if (isDragging()) {
1361         int selStart = _scint->SelectionStart().Position();
1362         int selEnd = _scint->SelectionEnd().Position();
1363         if (_scint->posDrop.Position() > selStart) {
1364           if (_scint->posDrop.Position() > selEnd)
1365             _scint->posDrop.SetPosition(_scint->posDrop.Position() - (selEnd-selStart));
1366           else
1367             _scint->posDrop.SetPosition(selStart);
1368           _scint->posDrop.SetPosition(_scint->pdoc->ClampPositionIntoDocument(_scint->posDrop.Position()));
1369         }
1370       }
1371       _scint->ClearSelection();
1372       }
1373     return 1;
1374     }
1375 
1376   return 0;
1377 }
1378 
1379 // ********************************************************************
1380 // Selection
1381 // ********************************************************************
1382 
1383 // We lost the selection somehow
onSelectionLost(FXObject * sender,FXSelector sel,void * ptr)1384 long FXScintilla::onSelectionLost(FXObject* sender,FXSelector sel,void* ptr){
1385   FXbool hadselection=hasSelection();
1386   FXScrollArea::onSelectionLost(sender,sel,ptr);
1387   if (hadselection) {
1388     _scint->UnclaimSelection();
1389   }
1390   return 1;
1391 }
1392 
1393 
1394 // Somebody wants our selection
onSelectionRequest(FXObject * sender,FXSelector sel,void * ptr)1395 long FXScintilla::onSelectionRequest(FXObject* sender,FXSelector sel,void* ptr){
1396   FXEvent *event=(FXEvent*)ptr;
1397   FXDragType types[]={utf8Type,stringType,0};
1398   // Perhaps the target wants to supply its own data for the selection
1399   if (FXScrollArea::onSelectionRequest(sender,sel,ptr)) { return 1; }
1400 
1401   for (FXDragType *dt=InUTF8Mode(_scint)?types:types+1; *dt; dt++) {
1402     // Return text of the selection
1403     if (event->target==*dt) {
1404       if (_scint->primary.Empty()) {
1405         _scint->CopySelectionRange(&_scint->primary);
1406       }
1407       if (!_scint->primary.Empty()) {
1408         setDNDData(FROM_SELECTION,*dt,(FXuchar *)strdup(_scint->primary.Data()),strlen(_scint->primary.Data()));
1409         return 1;
1410       }
1411     }
1412   }
1413   return 0;
1414 }
1415 
1416 // ********************************************************************
1417 // Scrolling
1418 // ********************************************************************
1419 
getViewportWidth()1420 FXint FXScintilla::getViewportWidth()
1421 {
1422   return _scint->GetTextRectangle().Width();
1423   //return FXScrollArea::getViewportWidth();
1424 }
1425 
getViewportHeight()1426 FXint FXScintilla::getViewportHeight()
1427 {
1428   //return (_scint) ? _scint->GetTextRectangle().Height() : FXScrollArea::getViewportHeight();
1429 #ifdef FOX_1_6
1430   return FXScrollArea::getViewportHeight();
1431 #else
1432   return FXScrollArea::getVisibleHeight();
1433 #endif
1434 }
1435 
getContentWidth()1436 FXint FXScintilla::getContentWidth()
1437 {
1438   return FXMAX(_scint->scrollWidth, 0);
1439 }
1440 
getContentHeight()1441 FXint FXScintilla::getContentHeight()
1442 {
1443   return
1444     _scint->cs.LinesDisplayed() * _scint->vs.lineHeight +
1445     // This part is a kind of magic, to have the correct scrollbar
1446     // behavior regarding the last line of the text
1447     (getViewportHeight() + _scint->vs.maxDescent) % _scint->vs.lineHeight;
1448 }
1449 
moveContents(FXint x,FXint y)1450 void FXScintilla::moveContents(FXint x,FXint y)
1451 {
1452   _scint->inMoveContents = true;
1453   bool moved = false;
1454   int line = (-y + _scint->vs.lineHeight / 2) / _scint->vs.lineHeight;
1455 
1456 #ifdef FOX_1_6
1457     if (line != getYPosition()/_scint->vs.lineHeight)
1458     {
1459     moved = true;
1460     _scint->ScrollTo(line);
1461   }
1462     if (x != getXPosition())
1463     {
1464     moved = true;
1465     _scint->HorizontalScrollTo(-x);
1466   }
1467 #else
1468   FXint gpx,gpy;
1469   getPosition(gpx,gpy);
1470   if (line != gpy/_scint->vs.lineHeight)
1471     {
1472     moved = true;
1473     _scint->ScrollTo(line);
1474   }
1475   getPosition(gpx,gpy);
1476   if (x != gpx)
1477     {
1478     moved = true;
1479     _scint->HorizontalScrollTo(-x);
1480   }
1481 
1482 #endif
1483 
1484   if (moved) {
1485     FXScrollArea::moveContents(x, -line * _scint->vs.lineHeight);
1486   }
1487   _scint->inMoveContents = false;
1488 }
1489 
onConfigure(FXObject * sender,FXSelector sel,void * ptr)1490 long FXScintilla::onConfigure(FXObject *sender, FXSelector sel, void * ptr)
1491 {
1492   long ret = FXScrollArea::onConfigure(sender, sel, ptr);
1493   _scint->ChangeSize();
1494   return ret;
1495 }
1496 
1497 // ********************************************************************
1498 // Messenging
1499 // ********************************************************************
1500 
setScintillaID(int sid)1501 void FXScintilla::setScintillaID(int sid)
1502 {
1503   _scint->ctrlID = sid;
1504 }
1505 
sendMessage(unsigned int iMessage,uptr_t wParam,sptr_t lParam)1506 sptr_t FXScintilla::sendMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
1507   return _scint->WndProc(iMessage, wParam, lParam);
1508 }
1509 
1510 
1511