AxWin3 - Heaps of bugfixes to RichText renderer
authorJohn Hodge <[email protected]>
Sat, 13 Oct 2012 08:01:42 +0000 (16:01 +0800)
committerJohn Hodge <[email protected]>
Sat, 13 Oct 2012 08:01:42 +0000 (16:01 +0800)
12 files changed:
AcessNative/Makefile
AcessNative/acesskernel_src/Makefile
Usermode/Applications/axwin3_src/WM/include/wm.h
Usermode/Applications/axwin3_src/WM/include/wm_internals.h
Usermode/Applications/axwin3_src/WM/renderers/richtext.c
Usermode/Applications/axwin3_src/WM/renderers/widget.c
Usermode/Applications/axwin3_src/WM/renderers/widget/subwin.c
Usermode/Applications/axwin3_src/WM/video.c
Usermode/Applications/axwin3_src/WM/wm.c
Usermode/Applications/axwin3_src/libaxwin3.so_src/r_richtext.c
Usermode/Applications/gui_ate_src/main.c
Usermode/Libraries/libaxwin3.so_src/include_exp/axwin3/richtext.h

index c9cd481..7448f4f 100644 (file)
@@ -1,4 +1,6 @@
 
-all:
-       @$(MAKE) -C acesskernel_src
-       @$(MAKE) -C ld-acess_src
+.PHONY: all clean
+
+all clean:
+       @$(MAKE) -C acesskernel_src $@
+       @$(MAKE) -C ld-acess_src $@
index be21e45..b4b7c11 100644 (file)
@@ -44,7 +44,8 @@ ifeq ($(PLATFORM),win)
 endif\r
 ifeq ($(PLATFORM),lin)\r
        BIN := ../AcessKernel\r
-       CFLAGS +=\r
+       CFLAGS += \r
+       LDFLAGS += -lpthread\r
 endif\r
 \r
 .PHONY: all clean\r
index 27890ba..e060e24 100644 (file)
@@ -24,6 +24,8 @@
 #define WINFLAG_NODECORATE     0x00000002
 //! Window takes up all of screen
 #define WINFLAG_MAXIMIZED      0x00000004
+//! Window is contained within the parent
+#define WINFLAG_RELATIVE       0x00000008
 //! Window contents are valid
 #define WINFLAG_CLEAN          0x00000040
 //! All child windows are un-changed
@@ -52,6 +54,7 @@ extern void   WM_FocusWindow(tWindow *Destination);
 extern void    WM_RaiseWindow(tWindow *Window);
 extern void    WM_ShowWindow(tWindow *Window, int bShow);
 extern void    WM_DecorateWindow(tWindow *Window, int bDecorate);
+extern void    WM_SetRelative(tWindow *Window, int bRelativeToParent);
 extern int     WM_ResizeWindow(tWindow *Window, int W, int H);
 extern int     WM_MoveWindow(tWindow *Window, int X, int Y);
 extern int     WM_SendMessage(tWindow *Source, tWindow *Dest, int MessageID, int Length, const void *Data);
index 9ab29f8..45769e8 100644 (file)
@@ -41,8 +41,9 @@ struct sWindow
 
        // Position and dimensions
         int    X, Y;
-        int    RealW, RealH;
         int    W, H;
+        int    RealX, RealY;
+        int    RealW, RealH;
 
        void    *RenderBuffer;  //!< Cached copy of the rendered window
 };
index eca5765..3e0fa54 100644 (file)
@@ -7,25 +7,32 @@
  */
 #include <common.h>
 #include <wm_renderer.h>
+#include <wm_messages.h>
 #include <richtext_messages.h>
 #include <stdio.h>     // sscanf
+#include <string.h>    // memcpy
 
 #define LINES_PER_BLOCK        30
 
 // === TYPES ===
-typedef struct sRichText_LineBlock
+typedef struct sRichText_Line
 {
-       struct sRichText_LineBlock      *Next;
-        int    FirstLine;
-       char    *Lines[LINES_PER_BLOCK];
-} tRichText_LineBlock;
+       struct sRichText_Line   *Next;
+       struct sRichText_Line   *Prev;
+        int    Num;
+       // TODO: Pre-rendered cache?
+       short   ByteLength;
+       short   Space;
+       char    Data[];
+} tRichText_Line;
 typedef struct sRichText_Window
 {
         int    DispLines, DispCols;
         int    FirstVisRow, FirstVisCol;
         int    nLines, nCols;
         int    CursorRow, CursorCol;
-       tRichText_LineBlock     FirstBlock;
+       tRichText_Line  *FirstLine;
+       tRichText_Line  *FirstVisLine;
        tColour DefaultFG;
        tColour DefaultBG;
        tFont   *Font;
@@ -60,11 +67,16 @@ tWindow *Renderer_RichText_Create(int Flags)
        tWindow *ret = WM_CreateWindowStruct( sizeof(*info) );
        if(!ret)        return NULL;
        info = ret->RendererInfo;
-       // Everything starts at zero?
+       
+       // Initialise font.
+       int h;
+       WM_Render_GetTextDims(NULL, "yY!", 3, NULL, &h);
+       info->LineHeight = h;
+       
        return ret;
 }
 
-static inline int Renderer_RichText_RenderText_Act(tWindow *Window, tRichText_Window *info, int X, int Row, const char *Text, int Bytes, tColour FG, tColour BG)
+static inline int Renderer_RichText_RenderText_Act(tWindow *Window, tRichText_Window *info, int X, int Row, const char *Text, int Bytes, tColour FG, tColour BG, int Flags)
 {
         int    rwidth;
        // TODO: Fill only what is needed
@@ -72,6 +84,7 @@ static inline int Renderer_RichText_RenderText_Act(tWindow *Window, tRichText_Wi
                Window->W - X, info->LineHeight,
                BG
                );
+       // TODO: Bold, Italic, Underline
        rwidth = WM_Render_DrawText(Window,
                X, Row*info->LineHeight,
                Window->W - X, info->LineHeight,
@@ -86,9 +99,7 @@ void Renderer_RichText_RenderText(tWindow *Window, int Line, const char *Text)
        tRichText_Window        *info = Window->RendererInfo;
        tColour fg = info->DefaultFG;
        tColour bg = info->DefaultBG;
-        int    bBold = 0;
-        int    bULine = 0;
-        int    bItalic = 0;
+        int    flagset = 0;
         int    bRender = 0;
         int    curx = 0;
        const char      *oldtext = Text;
@@ -106,7 +117,7 @@ void Renderer_RichText_RenderText(tWindow *Window, int Line, const char *Text)
                if( ch <=3 && bRender ) {
                        // Render previous characters
                        curx += Renderer_RichText_RenderText_Act(Window, info, curx, Line,
-                               oldtext, Text - oldtext, fg, bg);
+                               oldtext, Text - oldtext, fg, bg, flagset);
                        oldtext = Text;
                }
                switch(ch)
@@ -131,53 +142,68 @@ void Renderer_RichText_RenderText(tWindow *Window, int Line, const char *Text)
                                // Bad client
                        }
                        Text += len;
-                       bItalic = !!(flags & (1 << 2));
-                       bULine = !!(flags & (1 << 1));
-                       bBold = !!(flags & (1 << 0));
+                       //bItalic = !!(flags & (1 << 2));
+                       //bULine = !!(flags & (1 << 1));
+                       //bBold = !!(flags & (1 << 0));
+                       flagset = flags & 7;
                        break ;
                default: // Any char, nop
                        break;
                }
        }
-       curx += Renderer_RichText_RenderText_Act(Window, info, curx, Line, oldtext, Text - oldtext, fg, bg);
-       WM_Render_DrawRect(Window, curx, Line * info->LineHeight, Window->W - curx, info->LineHeight, info->DefaultBG);
+       curx += Renderer_RichText_RenderText_Act(Window, info, curx,
+               Line, oldtext, Text - oldtext, fg, bg, flagset);
+       WM_Render_DrawRect(Window, curx, Line * info->LineHeight,
+               Window->W - curx, info->LineHeight, info->DefaultBG);
 }
 
 void Renderer_RichText_Redraw(tWindow *Window)
 {
        tRichText_Window        *info = Window->RendererInfo;
         int    i;
-       tRichText_LineBlock     *lines = &info->FirstBlock;
+       tRichText_Line  *line = info->FirstVisLine;
        
-       // Locate the first line block
-       for( i = info->FirstVisRow; i > LINES_PER_BLOCK && lines; i -= LINES_PER_BLOCK )
-               lines = lines->Next;
+       if( !line ) {
+               line = info->FirstLine;
+               while(line && line->Num < info->FirstVisRow )
+                       line = line->Next;
+               info->FirstVisLine = line;
+       }
+       while( line && line->Prev && line->Prev->Num > info->FirstVisRow )
+               line = line->Prev;
 
-       for( i = 0; i < info->DispLines && lines; i ++ )
+       for( i = 0; i < info->DispLines && line; i ++ )
        {
                if( i >= info->nLines - info->FirstVisRow )
                        break;
                // TODO: Dirty rectangles?
-               WM_Render_DrawRect(Window,
+               WM_Render_FillRect(Window,
                        0, i*info->LineHeight,
                        Window->W, info->LineHeight,
                        info->DefaultBG
                        );
+               if( line->Num > info->FirstVisRow + i )
+                       continue ;
                // TODO: Horizontal scrolling?
                // TODO: Formatting
-               //Renderer_RichText_RenderText(Window, i, lines->Lines[i % LINES_PER_BLOCK]);
+               
+               // NOTE: uses scanf() so commented out for now
+               //Renderer_RichText_RenderText(Window, i, line->Text);
                WM_Render_DrawText(Window,
                        0, i*info->LineHeight,
                        Window->W, info->LineHeight,
                        info->Font, info->DefaultFG,
-                       lines->Lines[i % LINES_PER_BLOCK],
+                       line->Data,
                        -1);
-       
-               if( (i + 1) % LINES_PER_BLOCK == 0 )
-                       lines = lines->Next;
+               _SysDebug("RichText: %p - Render %i '%.*s'", Window,
+                       line->Num, line->ByteLength, line->Data);
+
+               line = line->Next;
        }
        // Clear out i -- info->DispLines
-       WM_Render_DrawRect(Window,
+       _SysDebug("RichText: %p - Clear %i px lines with %06x starting at %i",
+               Window, (info->DispLines-i)*info->LineHeight, info->DefaultBG, i*info->LineHeight);
+       WM_Render_FillRect(Window,
                0, i*info->LineHeight,
                Window->W, (info->DispLines-i)*info->LineHeight,
                info->DefaultBG
@@ -186,10 +212,81 @@ void Renderer_RichText_Redraw(tWindow *Window)
 
 int Renderer_RichText_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
 {
+       tRichText_Window        *info = Target->RendererInfo;
        switch(Msg)
        {
-       case MSG_RICHTEXT_SETATTR:
-               break;
+       case WNDMSG_RESIZE: {
+               const struct sWndMsg_Resize *msg = Data;
+               if(Len < sizeof(*msg))  return -1;
+               info->DispLines = msg->H / info->LineHeight;
+               return 1; }
+       case MSG_RICHTEXT_SETATTR: {
+               const struct sRichTextMsg_SetAttr *msg = Data;
+               if(Len < sizeof(*msg))  return -1;
+               _SysDebug("RichText Attr %i set to %x", msg->Attr, msg->Value);
+               switch(msg->Attr)
+               {
+               case _ATTR_DEFBG:
+                       info->DefaultBG = msg->Value;
+                       break;
+               case _ATTR_DEFFG:
+                       info->DefaultFG = msg->Value;
+                       break;
+               case _ATTR_SCROLL:
+                       // TODO: Set scroll flag
+                       break;
+               case _ATTR_LINECOUNT:
+                       info->nLines = msg->Value;
+                       break;
+               }
+               return 1; }
+       // Update a line
+       case MSG_RICHTEXT_SENDLINE: {
+               const struct sRichTextMsg_SendLine      *msg = Data;
+               if(Len < sizeof(*msg))  return -1;
+               _SysDebug("RichText Line %i = '%.*s'", msg->Line, Len - sizeof(*msg), msg->LineData);
+               if( msg->Line >= info->nLines ) return 1;       // Bad count
+               
+               tRichText_Line  *line = info->FirstLine;
+               tRichText_Line  *prev = NULL;
+               while(line && line->Num < msg->Line)
+                       prev = line, line = line->Next;
+               if( !line || line->Num > msg->Line )
+               {
+                       // New line!
+                       // Round up to 32
+                        int    space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
+                       tRichText_Line  *new = malloc(sizeof(*line) + space);
+                       // TODO: Bookkeeping on how much memory each window uses
+                       new->Next = line;
+                       new->Prev = prev;
+                       new->Num = msg->Line;
+                       new->Space = space;
+                       if(new->Prev)   new->Prev->Next = new;
+                       else    info->FirstLine = new;
+                       if(new->Next)   new->Next->Prev = new;
+                       line = new;
+               }
+               else if( line->Space < Len - sizeof(*msg) )
+               {
+                       // Need to allocate more space
+                        int    space = ((Len - sizeof(*msg)) + 32-1) & ~(32-1);
+                       tRichText_Line *new = realloc(line, space);
+                       // TODO: Bookkeeping on how much memory each window uses
+                       new->Space = space;
+
+                       if(new->Prev)   new->Prev->Next = new;
+                       else    info->FirstLine = new;
+                       if(new->Next)   new->Next->Prev = new;
+                       line = new;
+               }
+               else
+               {
+                       // It fits :)
+               }
+               line->ByteLength = Len - sizeof(*msg);
+               memcpy(line->Data, msg->LineData, Len - sizeof(*msg));
+               return 1; }
        }
        return 0;
 }
index 8852954..b8c454c 100644 (file)
@@ -87,7 +87,7 @@ tWindow       *Renderer_Widget_Create(int Flags)
        tWidgetWin      *info;
         int    eletable_size = DEFAULT_ELETABLE_SIZE;
 
-       _SysDebug("Renderer_Widget_Create: (Flags = 0x%x)", Flags);
+       //_SysDebug("Renderer_Widget_Create: (Flags = 0x%x)", Flags);
 
        // TODO: Use `Flags` as default element count?
        // - Actaully, it's taken by the root ele flags
@@ -214,14 +214,14 @@ void Widget_UpdateDimensions(tElement *Element)
        else
                fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
 
-       _SysDebug("%i (p=%i) - WxH=%ix%i",
-               Element->ID, (Element->Parent ? Element->Parent->ID : -1),
-               Element->CachedW, Element->CachedH
-               );
-       _SysDebug("  %s dynWith = %i, fullCross = %i",
-               (Element->Flags & ELEFLAG_VERTICAL ? "Vert" : "Horiz"),
-               dynWith, fullCross
-               );
+       //_SysDebug("%i (p=%i) - WxH=%ix%i",
+       //      Element->ID, (Element->Parent ? Element->Parent->ID : -1),
+       //      Element->CachedW, Element->CachedH
+       //      );
+       //_SysDebug("  %s dynWith = %i, fullCross = %i",
+       //      (Element->Flags & ELEFLAG_VERTICAL ? "Vert" : "Horiz"),
+       //      dynWith, fullCross
+       //      );
        
        // Pass 2 - Set sizes and recurse
        for( child = Element->FirstChild; child; child = child->NextSibling )
index 4cdaaba..fcf196d 100644 (file)
@@ -11,6 +11,8 @@
 
 void Widget_SubWin_Render(tWindow *Window, tElement *Element)
 {
+       // Ensure that child window is positioned relative to this window
+       WM_SetRelative(Element->Data, 1);
        // Note: Doesn't actually render, but does poke the child window
        WM_MoveWindow(Element->Data, Element->CachedX, Element->CachedY);
        WM_ResizeWindow(Element->Data, Element->CachedW, Element->CachedH);
@@ -20,4 +22,3 @@ DEFWIDGETTYPE(ELETYPE_SUBWIN,
        WIDGETTYPE_FLAG_NOCHILDREN,
        .Render = Widget_SubWin_Render
        )
-
index fe37964..1c857fb 100644 (file)
@@ -133,8 +133,6 @@ void Video_Blit(uint32_t *Source, short DstX, short DstY, short W, short H)
 {
        uint32_t        *buf;
 
-       _SysDebug("Video_Blit: (%p, %i, %i, %i, %i)", Source, DstX, DstY, W, H);
-
        if( DstX >= giScreenWidth)      return ;
        if( DstY >= giScreenHeight)     return ;
        // TODO: Handle -ve X/Y by clipping
@@ -146,8 +144,6 @@ void Video_Blit(uint32_t *Source, short DstX, short DstY, short W, short H)
 
        if( W <= 0 || H <= 0 )  return;
 
-       _SysDebug(" - Resolved to (%p, %i, %i, %i, %i)", Source, DstX, DstY, W, H);
-
        if( DstX < giVideo_FirstDirtyLine )
                giVideo_FirstDirtyLine = DstY;
        if( DstY + H > giVideo_LastDirtyLine )
index 019ce5a..fe944e3 100644 (file)
@@ -216,16 +216,49 @@ void WM_DecorateWindow(tWindow *Window, int bDecorate)
        WM_Invalidate(Window);
 }
 
+void WM_SetRelative(tWindow *Window, int bRelativeToParent)
+{
+//     _SysDebug("WM_SetRelative: (%p{Parent=%p},%i)", Window, Window->Parent, bRelativeToParent);
+       // No meaning if no parent
+       if( !Window->Parent )
+               return ;
+
+       // Check that the flag is changing
+       if( !!bRelativeToParent == !!(Window->Flags & WINFLAG_RELATIVE) )
+               return ;
+
+       if( bRelativeToParent ) {
+               // Set
+               Window->Flags |= WINFLAG_RELATIVE;
+               WM_MoveWindow(Window, Window->X, Window->Y);
+       }
+       else {
+               // Clear
+               Window->Flags &= ~WINFLAG_RELATIVE;
+               WM_MoveWindow(Window, Window->X - Window->Parent->X, Window->Y - Window->Parent->Y);
+       }
+}
+
 int WM_MoveWindow(tWindow *Window, int X, int Y)
 {
+//     _SysDebug("Move %p to (%i,%i)", Window, X, Y);
        // Clip coordinates
        if(X + Window->W < 0)   X = -Window->W + 1;
        if(Y + Window->H < 0)   Y = -Window->H + 1;
        if(X >= giScreenWidth)  X = giScreenWidth - 1;
        if(Y >= giScreenHeight) Y = giScreenHeight - 1;
        
+       // If relative to the parent, extra checks
+       if( (Window->Flags & WINFLAG_RELATIVE) && Window->Parent )
+       {
+               if( X > Window->Parent->W )     return 1;
+               if( Y > Window->Parent->H )     return 1;
+       }
+       // TODO: Re-sanitise
+
        Window->X = X;  Window->Y = Y;
 
+       // TODO: Why invalidate buffer?
        WM_Invalidate(Window);
 
        return 0;
@@ -301,7 +334,7 @@ int WM_SendMessage(tWindow *Source, tWindow *Dest, int Message, int Length, cons
 void WM_Invalidate(tWindow *Window)
 {
        if(!Window)     return ;
-       _SysDebug("Invalidating %p", Window);
+//     _SysDebug("Invalidating %p", Window);
        // Don't invalidate twice (speedup)
 //     if( !(Window->Flags & WINFLAG_CLEAN) )  return;
 
@@ -328,7 +361,7 @@ void WM_int_UpdateWindow(tWindow *Window)
                // Calculate RealW/RealH
                if( !(Window->Flags & WINFLAG_NODECORATE) )
                {
-                       _SysDebug("Applying decorations to %p", Window);
+                       //_SysDebug("Applying decorations to %p", Window);
                        Decorator_UpdateBorderSize(Window);
                        Window->RealW = Window->BorderL + Window->W + Window->BorderR;
                        Window->RealH = Window->BorderT + Window->H + Window->BorderB;
@@ -344,6 +377,17 @@ void WM_int_UpdateWindow(tWindow *Window)
                        Window->RealH = Window->H;
                }
                
+               if( (Window->Flags & WINFLAG_RELATIVE) && Window->Parent )
+               {
+                       Window->RealX = Window->Parent->X + Window->Parent->BorderL + Window->X;
+                       Window->RealY = Window->Parent->Y + Window->Parent->BorderT + Window->Y;
+               }
+               else
+               {
+                       Window->RealX = Window->X;
+                       Window->RealY = Window->Y;
+               }
+
                Window->Renderer->Redraw(Window);
                Window->Flags |= WINFLAG_CLEAN;
        }
@@ -371,15 +415,15 @@ void WM_int_BlitWindow(tWindow *Window)
        if( !(Window->Flags & WINFLAG_SHOW) )
                return ;
 
-       _SysDebug("Blit %p (%p) to (%i,%i) %ix%i", Window, Window->RenderBuffer,
-               Window->X, Window->Y, Window->RealW, Window->RealH);
-       Video_Blit(Window->RenderBuffer, Window->X, Window->Y, Window->RealW, Window->RealH);
+//     _SysDebug("Blit %p (%p) to (%i,%i) %ix%i", Window, Window->RenderBuffer,
+//             Window->RealX, Window->RealY, Window->RealW, Window->RealH);
+       Video_Blit(Window->RenderBuffer, Window->RealX, Window->RealY, Window->RealW, Window->RealH);
        
        if( Window == gpWM_FocusedWindow && Window->CursorW )
        {
                Video_FillRect(
-                       Window->X + Window->BorderL + Window->CursorX,
-                       Window->Y + Window->BorderT + Window->CursorY,
+                       Window->RealX + Window->BorderL + Window->CursorX,
+                       Window->RealY + Window->BorderT + Window->CursorY,
                        Window->CursorW, Window->CursorH,
                        0x000000
                        );
index 74b437b..b1620dd 100644 (file)
@@ -9,6 +9,8 @@
 #include <axwin3/richtext.h>
 #include "include/internal.h"
 #include <richtext_messages.h>
+#include <string.h>
+//#include <alloca.h>
 
 // === TYPES ===
 typedef struct sRichText_Window
@@ -89,3 +91,16 @@ void AxWin3_RichText_SetCursorPos(tHWND Window, int Row, int Column)
                return ;
        _SendAttrib(Window, _ATTR_CURSORPOS, ((Row & 0xFFFFF) << 12) | (Column & 0xFFF));
 }
+
+void AxWin3_RichText_SendLine(tHWND Window, int Line, const char *Text)
+{
+       // TODO: Local sanity check on `Line`?
+       struct sRichTextMsg_SendLine    *msg;
+       size_t  len = sizeof(*msg) + strlen(Text) + 1;
+       char    buffer[len];
+               msg = (void*)buffer;
+       msg->Line = Line;
+       strcpy(msg->LineData, Text);
+       AxWin3_SendMessage(Window, Window, MSG_RICHTEXT_SENDLINE, len, msg);
+}
+
index e83ab7c..82a9117 100644 (file)
@@ -33,7 +33,7 @@ int main(int argc, char *argv[])
        AxWin3_Connect(NULL);
        
        // --- Build up window
-       gMainWindow = AxWin3_Widget_CreateWindow(NULL, 400, 600, ELEFLAG_VERTICAL);
+       gMainWindow = AxWin3_Widget_CreateWindow(NULL, 600, 400, ELEFLAG_VERTICAL);
        AxWin3_SetWindowTitle(gMainWindow, "Acess Text Editor");        // TODO: Update title with other info
        gMainWindow_Root = AxWin3_Widget_GetRoot(gMainWindow);
 
@@ -69,6 +69,13 @@ int main(int argc, char *argv[])
        AxWin3_RichText_SetCursorPos    (gMainWindow_TextArea, 0, 0);
        AxWin3_RichText_SetCursorType   (gMainWindow_TextArea, AXWIN3_RICHTEXT_CURSOR_VLINE);
        AxWin3_RichText_SetCursorBlink  (gMainWindow_TextArea, 1);
+
+       // <testing>
+       AxWin3_RichText_SetLineCount(gMainWindow_TextArea, 3);
+       AxWin3_RichText_SendLine(gMainWindow_TextArea, 0, "First line!");
+       AxWin3_RichText_SendLine(gMainWindow_TextArea, 2, "Third line!, should be a nice gap above");
+       // </testing>
+
        AxWin3_ShowWindow(gMainWindow_TextArea, 1);
        // TODO: Status Bar?
 
index 2a6c5ae..661c02b 100644 (file)
@@ -39,6 +39,7 @@ extern void   AxWin3_RichText_SetFont(tHWND Window, const char *FontName, int Poin
 extern void    AxWin3_RichText_SetCursorType(tHWND Window, int Type);
 extern void    AxWin3_RichText_SetCursorBlink(tHWND Window, int bBlink);
 extern void    AxWin3_RichText_SetCursorPos(tHWND Window, int Row, int Column);
+extern void    AxWin3_RichText_SendLine(tHWND Window, int Line, const char *Text);
 
 #endif
 

UCC git Repository :: git.ucc.asn.au