FXStyledText

Page updated: 06/26/2001
Last version: scintillafox-0.2.tar.gz
View download statistic
 

INTRO:

FXStyledText is a FOX toolkit implementation of the Scintilla source code edit control.

Scintilla is a free, platform, and toolkit independent edit control with built-in functions for editing, styling (colors/fonts), error indicators, code completion, call tips, searching, auto indentation, brace highlighting, macro recording, printing, folding, selection margins, custom lexers and more.

FOX is a free, platform independent toolkit for creating Graphical User Interfaces. It offers a wide range of controls, and provides all the standard facilities such as drag and drop, selection, as well as OpenGL widgets. FOX has a powerful event mechanism, which can be used to pass commands between widgets, or to maintain the visual state of the controls.

This code is based on the wxStyledTextCtrl a WXWindows toolkit implementation of Scintilla.

SOURCES:

1. The FOX toolkit: http://www.cfdrc.com/FOX/fox.html
2. The Scintilla edit control: http://www.scintilla.org
3. The FXStyledText: http://www.cs.bc.edu/~fox
 

CREDITS:

1. The FOX toolkit: Jeroen van der Zijp <jeroen@fox-toolkit.org>
2. The Scintilla edit control: Neil Hodgson <neilh@scintilla.org>
3. The wxStyledTextCtrl: Robin Dunn <robin@aldunn.com>
4. The FXStyledText: Stefan Bokor <bokor@bc.edu>
 

STATUS of the version 0.2 (06/25/01):

Alpha - for developers only. Much work needs to be done. This version has been developed using fox-0.99.172 and scintilla-1.38.
The test aplication 'seditor' is able to:
  1. Load files and display them properly colorized based on the language  (only *.cpp tested).
  2. Basic keyboard operations work (insert/delete/home/end/pgup/pgdown and cursor keys). The control keys are not implemented yet.
  3. Scrolling works (horizontal scrolling needs some work).
  4. Drag-and-drop to/from works.
  5. Clipboard operations (copy/cut/paste) to/from work.
  6. Undo/Redo works.
  7. X selection (copy/paste) to/from works.
  8. Selection margins work (only the 'LineNumber' margin is functional).
  9. 'GoTo line' dialog implemented.
  10. Autoscroll while draging a selection works.
  11. Autoscroll while extending selection works.
  12. Context PopUp (copy/cut/paste/delete/select-all) implemented.
Current TODO list:
  1. Verify that the current design is feasible.
  2. Verify that the functions impementing the platform (FOX) depended layer are correct and efficient (file Platform.h and PlatFOX.cpp).
  3. Verify that the functions implementing the communication between the platform (FOX) and the Scintilla proper are correct and efficient (files ScintillaFOX.h and ScintillaFOX.cpp).
  4. Verify that the implementation of the FXStyledText is consistent with the rest of the FOX toolkit (files stc.h and stc.cpp).
  5. Start testing on the Windows platform - currently the development and testing is done on the Linux (KDE2) platform.
Once the above has been verified, we can implement (expose) the more advanced Scintilla function (code completion, call tips, folding...).
 

DESIGN:

The design is based on the architecture developed by Robin Dunn for the WXWindows version of the Scintilla control. The following diagram is a slightly modified version of the original (by Robin Dunn) taken from the WXWindows distribution.
 
                +------------------+          +-------------------+
4.FOX widget -> |   FXStyledText   |--bridge--|    ScintillaFX    | <- 3.communication layer
                +------------------+          +-------------------+
                                              |   ScintillaBase   |
                                              +-------------------+ <- 2.Scintilla proper
                                              |       Editor      |
                                              +-------------------+
                                              |      PlatFOX      | <- 1.platform layer
                                              +-------------------+

The following discussion assumes that the Scintille has been installed in $SCINTILLA (e.g.: /usr/local/scintilla)
 

1. The platform layer:
Scintilla achives the platform independece by providing a Portability library (defined in file $SCINTILLA/include/Platform.h). The Portability library is a thin layer over the platform's native capabilities. The objects defined by this layer are:

The FOX implementation of these objects is in the file $SCINTILLA/fox/PlatFOX.cpp.
 

2. The Scintilla proper:
Developers of a platform implementation will access the Scintilla capabilities via two classes: the Editor and the ScintillaBase. The Editor object is central to Scintilla. It is responsible for displaying a document and responding to user actions and requests from the container. ScintillaBase is a subclass of Editor and adds extra windowing features including display of calltips, autocompletion lists and context menus.
These two classes are implemented in files $SCINTILLA/src/Editor.cxx and $SCINTILLA/src/ScintillaBase.cxx.
 

3. The communication layer:
For each platform, a class is derived from ScintillaBase (and thus from Editor). These classes are responsible for connecting to the platforms event mechanism and also to implement some virtual methods in Editor and ScintillaBase.
The current implementation of the FOX communication layer uses messages. (In theory a different API, where the Scintilla events are directly translated into FOX events, could be implemented.)
The FOX implementation is in the file $SCINTILLA/fox/ScintillaFOX.cpp.

For more info on the Scintilla design please see http://www.scintilla.org/Design.html
 

4. The FOX styled widget:
The FXStyledText is derived from FXScrollArea which provides the drawing surface Scintilla will draw upon. When the FXStyledText is constructed it instanciates a ScintillaFX object and passes it itself as the argument:

     ScintillaFX* m_sfx = new ScintillaFX(this);

The FXStyledText will use the ScintillaFX object to access the 'low level' Editor functions exposed via public functions implemented in the ScintillaFOX.cpp e.g:

     m_sfx->DoAddChar(ch);

The ScintillaFX class will use the pointer to to the FXStyledText (received as a argument) to manipulate the container on behalf of the Scintilla proper, e.g.:

     ScintillaFX::ScintillaFX(FXStyledText* win) {stc=win};
     stc->moveContents(stc->pos_x, new_y);

The FXStyledText is implemented in the file $SCINTILLA/fox/stc.cpp, the ScintillaFX is implemented in the file $SCINTILLA/fox/ScintillaFOX.cpp.
 

5. The bridge:
To access the 'high level' (user) functions in the Scintilla, FXStyledText sends messages to the Scintilla proper. (These are similar to the Windows messages.) This is the mechanism used by both the WXWindows and the GTK version of the Scintilla.
The messages are wrapped in FXStyledText public functions e.g.:

     public void FXStyledText::ClearAll() {SendMsg(2004, 0, 0);}

These wrappers are the only functions the user of the FXStyledText should use to access the Scintilla capabilities!
The message wrappers are implemented in the file $SCINTILLA/fox/Messages.h. This file is #include-d in $SCINTILLA/fox/stc.h.

The Scintilla proper sends status messages back to FXStyledText, via FOX event mechanism! (Note: in the current version (0.2) the functions are impemented, but the status information is not used.)
The relevant code:

In ScintillaFox.cpp:

     void ScintillaFX::NotifyParent(SCNotification scn) {
       stc->handle(FXSciObject(wMain.GetID()), MKUINT(ID_SCINTILLA, SCIMSG_NOTIFY), &scn);
     }

Where:
     #define FXSciObject(a) ((FXObject* ) a)    //in $SCINTILLA/fox/ScintillaFOX.h
     Window wMain;                              //in $SCINTILLA/src/Editor.h

And in stc.cpp:

     long FXStyledText::onSciNotify(FXObject*, FXSelector, void*){...}
 

EXAMPLE1:
The following pseudo-code will attempt to ilustrate the design by investigating what happens on a key press. Using the 'seditor' example aplication.

A. The 'seditor' is started and a FXSTyledText object (editor) is instantiated (file seditor.cpp):

        editor = new FXStyledText(textbox, this, ID_TEXT);

B. The FXStyledText constructor will instantiate a ScintillaFX object (m_sfx) (file stc.cpp):

        m_sfx = new ScintillaFX(this);

C. Key press is detected by FXStyledText. The onKeyPress() function is called. From within onKeyPress() FOX calls the ScintillaFX function DoKeyDown(), and sends itself an ID_INSERT_CHAR message (file stc.cpp):

        long FXStyledText::onKeyPress(FXObject*, FXSelector, void*) {
          code = ...;
          key  = ...;
          m_sfx->DoKeyDown(code);
          handle(this, MKUINT(ID_INSERT_CHAR, SEL_COMMAND), key);
        }

D. FXStyledText handles the message in onCmdInsertChar() by calling the ScintillaFX  function DoAddChar() (file stc.cpp):

        long FXStyledText::onCmdInsertChar(FXObject*, FXSelector, void*) {
          ch = ...;
          m_sfx->DoAddChar(ch);
        }

E. ScintillaFX executes the DoAddChar() function by calling the Editor::AddChar(ch) function (file ScintillaFOX.cpp):

        void ScintillaFX::DoAddChar(char ch) {
          AddChar(ch);
        }

F. Editor'll add the character to its internal buffer, do the styling, display and all the magic, and sends a notification message to ScintillaFX with the details about the changes (file Editor.cpp):

        void Editor::AddChar(char ch) {
          Document* pdoc = ...;
          pdoc->InsertString(ch);
          NotifyParent(SCN_CHARADDED);
        }

G. ScintillFX receives the notification and forwards it to FOX as a FOX event (file ScintillaFOX.cpp):

        void ScintillaFX::NotifyParent(SCNotification scn) {
          stc->handle(FXSciObject(wMain.GetID()), MKUINT(ID_SCINTILLA, SCIMSG_NOTIFY), &scn);
        }

H. FXStyledText receives the event and handles it in onSciNotify() (file stc.cpp):

        long FXStyledText::onSciNotify(FXObject*, FXSelector, void*){...}

Please note that in the above example 'seditor' didn't use the message mechanism to access Scintilla, instead the FOX events were used to comunicate the request to the FXStyledText, which delegated the request to ScintillaFX, which on turn called the Editor functions directly.

The request:
     seditor -[FOX event]-> FXStyledText -> ScintillaFX -> Editor
The response:
     Editor -> ScintillaFX -[FOX event]-> FXStyledText
 

EXAMPLE2:
The second ilustration will show how a message is used by the aplication to access Scintilla. We will investigate what happens when the example aplication 'seditor' opens a disk file for editing.

A. The 'seditor' is started and a FXSTyledText object (editor) is instantiated (file seditor.cpp):

        editor = new FXStyledText(textbox, this, ID_TEXT);

B. The FXStyledText constructor will instantiate a ScintillaFX object (m_sfx) (file stc.cpp):

        m_sfx = new ScintillaFX(this);

C. The user selects the 'Open' menu item. Seditor calls the function LoadFile(), where it reads the disk file into a buffer and calls the FXStyledText function SetText() (file seditor.cpp):

       FXbool StyledTextWindow::LoadFile(const FXString& file) {
         fread(buffer, file);
         editor->SetText(buffer);
       }

D. The called function FXStyledText::SetText() is a wrapper function which will send a message to Scintilla proper requesting the 'buffer' to be styled and displayed (file Messages.h):

        void SetText(const FXString& buffer) {
          SendMsg(2181, 0, (long)buffer.text());
        }

E. The messages 2181 (defined as SCI_SETTEXT in file $SCINTILLA/include/Scintilla.h) is received by the Editor and the requested action is performed (file Editor.cxx):

        Document* pdoc = ...;
        switch (iMessage) {
          case SCI_SETTEXT: pdoc->InsertString(0, lParam);
          ...
        }

F. Finally Editor will display the text and send a notification to ScintillaFX, which forwards the message to FXStyledText as a FOX event - as in F. G. H. in the previous example.

The request:
     seditor -> FXStyledText -[Scintilla message]-> Editor
The response:
     Editor -> ScintillaFX -[FOX event]-> FXStyledText
 

IMPLEMENTATION:

This section describes briefly each file used in the implementation (ver. 0.2).

1. Platform.h ($SCINTILLA/include/Platform.h): This file is part of the Scintilla distribution, and it needs to modified for each platform the control is being implemented for (see section DESIGN, paragraph 1). The following mapping between the Scintilla and the FOX objects has been made:

Further, as part of the Surface class FXDCWindow was choosen as the actual drawing surface, and FXImage as the object for painting. (I was unable to use FXBitmap due to a bug in the pre fox-0.99.173, not allowing for 1x1 bitmaps.)

2. PlatFox.cpp ($SCINTILLA/fox/PlatFox.cpp): This file implemets the mapping defined in the Platform.h file, and a few additional utility functions. This file is based on PlatWX.cpp from the WXWindows implementation.

Note for developers: Please verify the above two files. I (SB) have marked all functions I was not sure about with "//SB ?", where the number of question marks indicate my level of confusion :). Some of the functions are already exercised by the example 'seditor', and they appears to be working, but somebody who is more intimate with the FOX internals could probably improve those. Also the ListBox has not been implemented yet (The commented out WXWindow implementation has been left there as a clue.)

3. ScintillaFOX.h, ScintillaFOX.cpp ($SCINTILLA/fox/*): These files implement the required Scintilla virtuall functions and the 'delegate' functions DoXXX(). This file is based on ScintillaWX.cpp from the WXWindows implementation.

Note for developers: Please verify the functions implementing the scrolling. The vertical scrolling seems to be OK, but the horizontal scrolling needs some work. Scintilla doesn't provide the means for determining the width of the displayed contents (w_contents). Both the WXWindows and the GTK implementation are using hard-coded values, so does our code.
CallTipWindow is not implemented yet - the commented out code from ScintillaWX.cpp is there as a guide.
The DoButtonUp() function would normally call Editor::ButtonUp(), but the code in Editor conflicts with FOX DND, so we do our own handling here. Our code will also change the default behaviour when clicking on a selected area from NOP to removing the selection (With the default behaviour one must click on a non-selected region to remove the selection.)

4. stc.h, stc.cpp ($SCINTILLA/fox/*): The implementation of the FXStyledText widget. This file was created using the FXText.cpp as a guide.

Note for developers: Commented out fragments of code taken from FXText.cpp has been left in the file.
The LoadConfig() function is a temp, to load the CPP lexer, set the syntax colors, fonts, and initialize margins.
The functions getViewportHeight() and getViewportWidth() are taken from FXScrollArea.cpp - please check if this is the correct solution.
Scintilla doesn't have autoscroll-while-selecting and autoscroll-while-dragging. FXStyledText implemets both, but the function Editor::ButtonMove() must be patched. Please see the Editor.cpp and look for the "\\SB" comments.

5. Messages.h ($SCINTILLA/fox/Messages.h): This file implements the wrapper arround the Scintilla SendMsg() functions. This file has been extracted from stc.h in the WXWindows version.

Note for developers: Please verify the functions returning FXColor. (GetCaretForeground() etc)

6. seditor.h, seditor.cpp ($SCINTILLA/fox/*): An example editor to exercise the FXStyledText widget. The LoadFile() is taken from the fox textedit application.

7. Makefile ($SCINTILLA/fox/Makefile): Makefile for compiling the modified scintilla library and the 'seditor' application. Callable targets: dep - create .depend file, lib - create the scintila.a library, lex - create the parser object files (not part of the library), exe - create the 'seditor', and clean - delete object files and the library. The default target is equivalent to make lib; make lex; make exe.
 
 

INSTALLATION (Linux platform):

1. Install the Scintilla source files:

     $ cd /usr/local
     $ gzip -dc scintillaXXX.tgz | tar xvf -

(the XXX is the Scintilla version number)

2. Rename the new directory:

   $ mv scintilla scintilla138 (or a name of your choice)

3. The FXStyledText source files are distributed as a compressed tar archive. Please change to the directory where you unpacked the Scintilla sources and execute

     $ gzip -dc scintillafox-XX.tar.gz | tar xvf -

(the XX is the version number of the port, as of 06/25/01 the distribution file is scintillafox-0.2.tar.gz)

4. After unpacking the distro you will have a file scifox.patch in the $SCINTILLA directory, and a subdirectory $SCINTILLA/fox.
Read the $SCINTILLA/fox/README.html file, and verify that you are using the version of the FOX library and the version of the Scintilla the scintillafox distribution was developed with.

5. Apply the scifox.patch to add the FOX support to the Scintilla files:

     $ patch -p1 < scifox.patch

6. Change to the fox subdirectory and run:

    $ make dep
    $ make

7. Test the example aplication:

     $ ./seditor
 

Note for developers:

You are welcome to submit your changes in any format you choose. The prefered method is a patch file. Assuming the old scintilla directory is /usr/local/scintilla-old and the new (modified) is /usr/local/scintilla-new, you can create the patch files with:

    $ cd /usr/local
    $ diff -c -r scintilla-old scintilla-new > scifox.patch

Alernative is a tar archive of all files you have made changes to, sent to bokor@bc.edu as a email attachement. Credit to
the developers will be given on this page, and in the source files.
If we manage to assemble a small team I'll set up a mailing list. Until than please feel free to contact me by email, or post a message to the FOX newsgroup.

I hoped to do some more testing/cleaning before releasing the code, but it looks like I won't be able to work on this project until September. If anybody feels this work is worth spending time on, I would be glad to update the distro with his/her modifications and make it available from our server.
 

Stefan Bokor
bokor@bc.edu