-all:
- @$(MAKE) -C acesskernel_src
- @$(MAKE) -C ld-acess_src
+.PHONY: all clean
+
+all clean:
+ @$(MAKE) -C acesskernel_src $@
+ @$(MAKE) -C ld-acess_src $@
endif\r
ifeq ($(PLATFORM),lin)\r
BIN := ../AcessKernel\r
- CFLAGS +=\r
+ CFLAGS += \r
+ LDFLAGS += -lpthread\r
endif\r
\r
.PHONY: all clean\r
#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
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);
// 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
};
*/
#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;
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
Window->W - X, info->LineHeight,
BG
);
+ // TODO: Bold, Italic, Underline
rwidth = WM_Render_DrawText(Window,
X, Row*info->LineHeight,
Window->W - X, info->LineHeight,
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;
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)
// 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
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;
}
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
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 )
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);
WIDGETTYPE_FLAG_NOCHILDREN,
.Render = Widget_SubWin_Render
)
-
{
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
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 )
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;
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;
// 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;
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;
}
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
);
#include <axwin3/richtext.h>
#include "include/internal.h"
#include <richtext_messages.h>
+#include <string.h>
+//#include <alloca.h>
// === TYPES ===
typedef struct sRichText_Window
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);
+}
+
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);
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?
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