Add documentation for using styles in text editor.

Add placeholder for style attributes - hidden + underlined - for
future use.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@2301 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Michael R Sweet 2002-06-09 18:28:49 +00:00
parent 464c7d8ba5
commit c3cde61e98
4 changed files with 315 additions and 20 deletions

View File

@ -1,5 +1,5 @@
//
// "$Id: Fl_Text_Display.H,v 1.4.2.7 2002/06/08 12:51:38 easysw Exp $"
// "$Id: Fl_Text_Display.H,v 1.4.2.8 2002/06/09 18:28:48 easysw Exp $"
//
// Header file for Fl_Text_Display class.
//
@ -55,10 +55,18 @@ class Fl_Text_Display: public Fl_Group {
typedef void (*Unfinished_Style_Cb)();
// style attributes - currently not implemented!
enum {
ATTR_NONE = 0,
ATTR_UNDERLINE = 1,
ATTR_HIDDEN = 2
};
struct FL_EXPORT Style_Table_Entry {
Fl_Color color;
Fl_Font font;
int size;
Fl_Color color;
Fl_Font font;
int size;
unsigned attr;
};
FL_EXPORT Fl_Text_Display(int X, int Y, int W, int H, const char *l = 0);
@ -234,5 +242,5 @@ class Fl_Text_Display: public Fl_Group {
#endif
//
// End of "$Id: Fl_Text_Display.H,v 1.4.2.7 2002/06/08 12:51:38 easysw Exp $".
// End of "$Id: Fl_Text_Display.H,v 1.4.2.8 2002/06/09 18:28:48 easysw Exp $".
//

View File

@ -105,7 +105,7 @@ Fl_Menu_Item menuitems[] = {
<TT>Fl_Menu_Bar</TT> widget and assign the menus to it with:</P>
<UL><PRE>
Fl_Menu_Bar *m = new Fl_Menu_Bar(0, 0, 512, 30);
Fl_Menu_Bar *m = new Fl_Menu_Bar(0, 0, 640, 30);
m-&gt;copy(menuitems);
</PRE></UL>
@ -118,7 +118,7 @@ m-&gt;copy(menuitems);
widget to edit the text:
<UL><PRE>
w->editor = new Fl_Text_Editor(0, 30, 512, 354);
w->editor = new Fl_Text_Editor(0, 30, 640, 370);
w->editor->buffer(textbuf);
</PRE></UL>
@ -598,5 +598,287 @@ The final editor window should look like the image in Figure 4-2.
<P ALIGN="CENTER"><IMG src="editor.gif" ALT="The completed editor window."><BR>
<I>Figure 4-2: The completed editor window</I></P>
<H2>Advanced Features</H2>
<P>Now that we've implemented the basic functionality, it is
time to show off some of the advanced features of the
<CODE>Fl_Text_Editor</CODE> widget.
<H3>Syntax Highlighting</H3>
<P>The <CODE>Fl_Text_Editor</CODE> widget supports highlighting
of text with different fonts, colors, and sizes. The
implementation is based on the excellent <A
HREF="http://www.nedit.org/">NEdit</A> text editor core, which
uses a parallel "style" buffer which tracks the font, color, and
size of the text that is drawn.
<P>Styles are defined using the
<CODE>Fl_Text_Display::Style_Table_Entry</CODE> structure
defined in <CODE>&lt;FL/Fl_Text_Display.H></CODE>:
<UL><PRE>
struct Style_Table_Entry {
Fl_Color color;
Fl_Font font;
int size;
unsigned attr;
};
</PRE></UL>
<P>The <CODE>color</CODE> member sets the color for the text,
the <CODE>font</CODE> member sets the FLTK font index to use,
and the <CODE>size</CODE> member sets the pixel size of the
text. The <CODE>attr</CODE> member is currently not used.
<P>For our text editor we'll define 7 styles for plain code,
comments, keywords, and preprocessor directives:
<UL><PRE>
Fl_Text_Display::Style_Table_Entry styletable[] = { // Style table
{ FL_BLACK, FL_COURIER, FL_NORMAL_SIZE }, // A - Plain
{ FL_DARK_GREEN, FL_COURIER_ITALIC, FL_NORMAL_SIZE }, // B - Line comments
{ FL_DARK_GREEN, FL_COURIER_ITALIC, FL_NORMAL_SIZE }, // C - Block comments
{ FL_BLUE, FL_COURIER, FL_NORMAL_SIZE }, // D - Strings
{ FL_DARK_RED, FL_COURIER, FL_NORMAL_SIZE }, // E - Directives
{ FL_DARK_RED, FL_COURIER_BOLD, FL_NORMAL_SIZE }, // F - Types
{ FL_BLUE, FL_COURIER_BOLD, FL_NORMAL_SIZE } // G - Keywords
};
</PRE></UL>
<P>You'll notice that the comments show a letter next to each
style - each style in the style buffer is referenced using a
character starting with the letter 'A'.
<P>You call the <CODE>highlight_data()</CODE> method to associate the
style data and buffer with the text editor widget:
<UL><PRE>
Fl_Text_Buffer *stylebuf;
w->editor->highlight_data(stylebuf, styletable,
sizeof(styletable) / sizeof(styletable[0]),
'A', style_unfinished_cb, 0);
</PRE></UL>
<P>Finally, you need to add a callback to the main text buffer so
that changes to the text buffer are mirrored in the style buffer:
<UL><PRE>
textbuf->add_modify_callback(style_update, w->editor);
</PRE></UL>
<P>The <CODE>style_update()</CODE> function, like the <CODE>change_cb()</CODE>
function described earlier, is called whenever text is added or removed from
the text buffer. It mirrors the changes in the style buffer and then updates
the style data as necessary:
<UL><PRE>
//
// 'style_update()' - Update the style buffer...
//
void
style_update(int pos, // I - Position of update
int nInserted, // I - Number of inserted chars
int nDeleted, // I - Number of deleted chars
int nRestyled, // I - Number of restyled chars
const char *deletedText, // I - Text that was deleted
void *cbArg) { // I - Callback data
int start, // Start of text
end; // End of text
char last, // Last style on line
*style, // Style data
*text; // Text data
// If this is just a selection change, just unselect the style buffer...
if (nInserted == 0 &amp;&amp; nDeleted == 0) {
stylebuf->unselect();
return;
}
// Track changes in the text buffer...
if (nInserted > 0) {
// Insert characters into the style buffer...
style = new char[nInserted + 1];
memset(style, 'A', nInserted);
style[nInserted] = '\0';
stylebuf->replace(pos, pos + nDeleted, style);
delete[] style;
} else {
// Just delete characters in the style buffer...
stylebuf->remove(pos, pos + nDeleted);
}
// Select the area that was just updated to avoid unnecessary
// callbacks...
stylebuf->select(pos, pos + nInserted - nDeleted);
// Re-parse the changed region; we do this by parsing from the
// beginning of the line of the changed region to the end of
// the line of the changed region... Then we check the last
// style character and keep updating if we have a multi-line
// comment character...
start = textbuf->line_start(pos);
end = textbuf->line_end(pos + nInserted - nDeleted);
text = textbuf->text_range(start, end);
style = stylebuf->text_range(start, end);
last = style[end - start - 1];
style_parse(text, style, end - start);
stylebuf->replace(start, end, style);
((Fl_Text_Editor *)cbArg)->redisplay_range(start, end);
if (last != style[end - start - 1]) {
// The last character on the line changed styles, so reparse the
// remainder of the buffer...
free(text);
free(style);
end = textbuf->length();
text = textbuf->text_range(start, end);
style = stylebuf->text_range(start, end);
style_parse(text, style, end - start);
stylebuf->replace(start, end, style);
((Fl_Text_Editor *)cbArg)->redisplay_range(start, end);
}
free(text);
free(style);
}
</PRE></UL>
<P>The <CODE>style_parse()</CODE> function scans a copy of the
text in the buffer and generates the necessary style characters
for display. It assumes that parsing begins at the start of a line:
<UL><PRE>
//
// 'style_parse()' - Parse text and produce style data.
//
void
style_parse(const char *text,
char *style,
int length) {
char current;
int col;
int last;
char buf[255],
*bufptr;
const char *temp;
for (current = *style, col = 0, last = 0; length > 0; length --, text ++) {
if (current == 'A') {
// Check for directives, comments, strings, and keywords...
if (col == 0 &amp;&amp; *text == '#') {
// Set style to directive
current = 'E';
} else if (strncmp(text, "//", 2) == 0) {
current = 'B';
} else if (strncmp(text, "/*", 2) == 0) {
current = 'C';
} else if (strncmp(text, "\\\"", 2) == 0) {
// Quoted quote...
*style++ = current;
*style++ = current;
text ++;
length --;
col += 2;
continue;
} else if (*text == '\"') {
current = 'D';
} else if (!last &amp;&amp; islower(*text)) {
// Might be a keyword...
for (temp = text, bufptr = buf;
islower(*temp) &amp;&amp; bufptr &lt; (buf + sizeof(buf) - 1);
*bufptr++ = *temp++);
if (!islower(*temp)) {
*bufptr = '\0';
bufptr = buf;
if (bsearch(&amp;bufptr, code_types,
sizeof(code_types) / sizeof(code_types[0]),
sizeof(code_types[0]), compare_keywords)) {
while (text &lt; temp) {
*style++ = 'F';
text ++;
length --;
col ++;
}
text --;
length ++;
last = 1;
continue;
} else if (bsearch(&amp;bufptr, code_keywords,
sizeof(code_keywords) / sizeof(code_keywords[0]),
sizeof(code_keywords[0]), compare_keywords)) {
while (text &lt; temp) {
*style++ = 'G';
text ++;
length --;
col ++;
}
text --;
length ++;
last = 1;
continue;
}
}
}
} else if (current == 'C' &amp;&amp; strncmp(text, "*/", 2) == 0) {
// Close a C comment...
*style++ = current;
*style++ = current;
text ++;
length --;
current = 'A';
col += 2;
continue;
} else if (current == 'D') {
// Continuing in string...
if (strncmp(text, "\\\"", 2) == 0) {
// Quoted end quote...
*style++ = current;
*style++ = current;
text ++;
length --;
col += 2;
continue;
} else if (*text == '\"') {
// End quote...
*style++ = current;
col ++;
current = 'A';
continue;
}
}
// Copy style info...
if (current == 'A' &amp;&amp; (*text == '{' || *text == '}')) *style++ = 'G';
else *style++ = current;
col ++;
last = isalnum(*text) || *text == '.';
if (*text == '\n') {
// Reset column and possibly reset the style
col = 0;
if (current == 'B' || current == 'E') current = 'A';
}
}
}
</PRE></UL>
</BODY>
</HTML>

View File

@ -1,5 +1,5 @@
//
// "$Id: Fl_Text_Display.cxx,v 1.12.2.17 2002/06/09 13:35:49 easysw Exp $"
// "$Id: Fl_Text_Display.cxx,v 1.12.2.18 2002/06/09 18:28:49 easysw Exp $"
//
// Copyright 2001-2002 by Bill Spitzak and others.
// Original code Copyright Mark Edel. Permission to distribute under
@ -1045,7 +1045,11 @@ void Fl_Text_Display::draw_string( int style, int X, int Y, int toX,
Fl_Color background;
if ( style & STYLE_LOOKUP_MASK ) {
styleRec = &mStyleTable[ ( style & STYLE_LOOKUP_MASK ) - 'A' ];
int si = (style & STYLE_LOOKUP_MASK) - 'A';
if (si < 0) si = 0;
else if (si >= mNStyles) si = mNStyles - 1;
styleRec = mStyleTable + si;
font = styleRec->font;
size = styleRec->size;
@ -1234,8 +1238,12 @@ int Fl_Text_Display::string_width( const char *string, int length, int style ) {
int size;
if ( style & STYLE_LOOKUP_MASK ) {
font = mStyleTable[ ( style & STYLE_LOOKUP_MASK ) - 'A' ].font;
size = mStyleTable[ ( style & STYLE_LOOKUP_MASK ) - 'A' ].size;
int si = (style & STYLE_LOOKUP_MASK) - 'A';
if (si < 0) si = 0;
else if (si >= mNStyles) si = mNStyles - 1;
font = mStyleTable[si].font;
size = mStyleTable[si].size;
} else {
font = textfont();
size = textsize();
@ -1951,5 +1959,5 @@ int Fl_Text_Display::handle(int event) {
//
// End of "$Id: Fl_Text_Display.cxx,v 1.12.2.17 2002/06/09 13:35:49 easysw Exp $".
// End of "$Id: Fl_Text_Display.cxx,v 1.12.2.18 2002/06/09 18:28:49 easysw Exp $".
//

View File

@ -1,5 +1,5 @@
//
// "$Id: editor.cxx,v 1.2.2.3.2.8 2002/06/09 13:35:49 easysw Exp $"
// "$Id: editor.cxx,v 1.2.2.3.2.9 2002/06/09 18:28:49 easysw Exp $"
//
// A simple text editor program for the Fast Light Tool Kit (FLTK).
//
@ -57,8 +57,7 @@ Fl_Text_Buffer *textbuf = 0;
// Syntax highlighting stuff...
Fl_Text_Buffer *stylebuf = 0;
Fl_Text_Display::Style_Table_Entry
styletable[] =
{
styletable[] = { // Style table
{ FL_BLACK, FL_COURIER, FL_NORMAL_SIZE }, // A - Plain
{ FL_DARK_GREEN, FL_COURIER_ITALIC, FL_NORMAL_SIZE }, // B - Line comments
{ FL_DARK_GREEN, FL_COURIER_ITALIC, FL_NORMAL_SIZE }, // C - Block comments
@ -67,8 +66,7 @@ Fl_Text_Display::Style_Table_Entry
{ FL_DARK_RED, FL_COURIER_BOLD, FL_NORMAL_SIZE }, // F - Types
{ FL_BLUE, FL_COURIER_BOLD, FL_NORMAL_SIZE } // G - Keywords
};
const char *code_keywords[] = // List of known C/C++ keywords...
{
const char *code_keywords[] = { // List of known C/C++ keywords...
"and",
"and_eq",
"asm",
@ -104,8 +102,7 @@ const char *code_keywords[] = // List of known C/C++ keywords...
"xor",
"xor_eq"
};
const char *code_types[] = // List of known C/C++ types...
{
const char *code_types[] = { // List of known C/C++ types...
"auto",
"bool",
"char",
@ -764,5 +761,5 @@ int main(int argc, char **argv) {
}
//
// End of "$Id: editor.cxx,v 1.2.2.3.2.8 2002/06/09 13:35:49 easysw Exp $".
// End of "$Id: editor.cxx,v 1.2.2.3.2.9 2002/06/09 18:28:49 easysw Exp $".
//