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(©Text);
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(©Text);
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