freetype sample: update

git-svn-id: svn://kolibrios.org@6865 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Sergey Semyonov (Serge) 2017-02-16 14:51:37 +00:00
parent 98f098c030
commit ddda916673
14 changed files with 2103 additions and 283 deletions

View File

@ -1,29 +1,49 @@
CC = kos32-gcc CC = kos32-gcc
LD = kos32-ld LD = kos32-ld
AR = kos32-ar
SDK_DIR:= $(abspath ../../..) SDK_DIR:= $(abspath ../../..)
CONTRIB_DIR:= $(abspath ../../../..)
LDFLAGS = -static -S -nostdlib -T $(SDK_DIR)/sources/newlib/app.lds -Map txview.map --image-base 0 LDFLAGS = -static --subsystem native -Tapp-dynamic.lds -Map txview.map --image-base 0
CFLAGS = -c -fno-ident -O2 -fomit-frame-pointer -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 CFLAGS = -c -O2 -msse2 -fno-ident -U__WIN32__ -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32
INCLUDES= -I $(SDK_DIR)/sources/newlib/libc/include -I $(SDK_DIR)/sources/freetype/include INCLUDES= -I./winlib -I./pxdraw -I $(SDK_DIR)/sources/newlib/libc/include -I $(SDK_DIR)/sources/freetype/include
LIBPATH:= -L $(SDK_DIR)/lib -L /home/autobuild/tools/win32/mingw32/lib INCLUDES+= -I $(CONTRIB_DIR)/toolchain/binutils/bfd -I $(CONTRIB_DIR)/toolchain/binutils/include
LIBPATH:= -L./ -L $(SDK_DIR)/lib
LIB_SRCS= \
pxdraw/context.c \
pxdraw/dutils.c \
pxdraw/region.c \
winlib/button.c \
winlib/winlib.c \
$(NULL)
SOURCES = main.c \ SOURCES = main.c \
fontlib.c \ fontlib.c \
tview.c tview.c \
$(NULL)
LIB_OBJS = $(patsubst %.c, %.o, $(LIB_SRCS))
OBJECTS = $(patsubst %.c, %.o, $(SOURCES)) OBJECTS = $(patsubst %.c, %.o, $(SOURCES))
default: txview default: txview
txview: $(OBJECTS) Makefile libwin.a: $(LIB_OBJS) Makefile
$(LD) $(LDFLAGS) $(LIBPATH) -o txview $(OBJECTS) -lfreetype.dll -lpixlib.dll -lgcc -lc.dll -lapp $(AR) crs $@ $(LIB_OBJS)
objcopy txview -O binary
txview: $(OBJECTS) libwin.a Makefile
$(LD) $(LDFLAGS) $(LIBPATH) -o txview.dll $(OBJECTS) -lfreetype.dll -lpixlib3 -lwin -lgcc -lc.dll
# objdump -d txview.dll > txview.lst
objcopy txview.dll txview -O binary
clean:
/bin/rm -rf *.o txview
%.o : %.c Makefile $(SOURCES) %.o : %.c Makefile $(SOURCES)
$(CC) $(CFLAGS) $(INCLUDES) -o $@ $< $(CC) $(CFLAGS) $(INCLUDES) -o $@ $<

View File

@ -6,19 +6,12 @@
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_GLYPH_H #include FT_GLYPH_H
#include <pixlib2.h> #include <pxdraw.h>
typedef struct
{
int l;
int t;
int r;
int b;
}rect_t;
typedef struct typedef struct
{ {
FT_Face face; FT_Face face;
int fontsize;
int height; int height;
int base; int base;
@ -27,6 +20,9 @@ typedef struct
}font_t; }font_t;
static FT_Face def_face; static FT_Face def_face;
static FT_Face sym_face;
font_t *sym_font;
typedef unsigned int color_t; typedef unsigned int color_t;
@ -34,63 +30,37 @@ unsigned int ansi2utf32(unsigned char ch);
font_t *create_font(FT_Face face, int size); font_t *create_font(FT_Face face, int size);
void my_draw_bitmap(bitmap_t *win, FT_Bitmap *bitmap, int dstx, int dsty, int col) void draw_glyph(ctx_t *ctx, void *buffer, int pitch, rect_t *rc, color_t color);
unsigned int ansi2utf32(unsigned char ch)
{ {
uint8_t *dst; if(ch < 0x80)
uint8_t *src, *tmpsrc; return ch;
uint32_t *tmpdst; if(ch < 0xB0)
int i, j; return 0x410-0x80 + ch;
dst = win->data + dsty * win->pitch + dstx*4; if(ch < 0xE0)
src = bitmap->buffer; return 0;
// printf("buffer %x width %d rows %d\n", if(ch < 0xF0)
// bitmap->buffer, bitmap->width, bitmap->rows); return 0x440-0xE0 + ch;
if(ch == 0xF0)
for( i = 0; i < bitmap->rows; i++ ) return 0x401;
{ else if(ch==0xF1)
tmpdst = (uint32_t*)dst; return 0x451;
tmpsrc = src; else return 0;
dst+= win->pitch;
src+= bitmap->pitch;
for( j = 0; j < bitmap->width; j++)
{
int a = *tmpsrc++;
int sr, sg, sb;
int dr, dg, db;
if( a != 0) a++;
db = *tmpdst & 0xFF;
dg = (*tmpdst >> 8) & 0xFF;
dr = (*tmpdst >> 16) & 0xFF;
sb = col & 0xFF;
sg = (col >> 8) & 0xFF;
sr = (col >> 16) &0xFF;
db = (a*sb + db*(256-a))/256;
dg = (a*sg + dg*(256-a))/256;
dr = (a*sr + dr*(256-a))/256;
*tmpdst++ = 0xFF000000|(dr<<16)|(dg<<8)|db;
};
} }
};
int draw_text_ext(ctx_t *ctx, font_t *font, char *text, int len, rect_t *rc, color_t color)
int draw_text_ext(bitmap_t *winbitmap, font_t *font, char *text, int len, rect_t *rc, int color)
{ {
FT_UInt glyph_index; FT_UInt glyph_index;
FT_Bool use_kerning = 0; FT_Bool use_kerning = 0;
FT_BitmapGlyph glyph; FT_BitmapGlyph glyph;
FT_UInt previous; FT_UInt previous;
int x, y, w; int x, y, xend;
int col, ncol; int col, ncol;
unsigned char ch; unsigned char ch;
int err = 0; int err = 0;
@ -100,9 +70,8 @@ int draw_text_ext(bitmap_t *winbitmap, font_t *font, char *text, int len, rect_t
col = 0; col = 0;
x = rc->l << 6; x = rc->l << 6;
y = rc->b; xend = rc->r << 6;
y = rc->t + font->base;
w = (rc->r - rc->l) << 6;
while( len-- ) while( len-- )
{ {
@ -113,7 +82,7 @@ int draw_text_ext(bitmap_t *winbitmap, font_t *font, char *text, int len, rect_t
if(ch == '\t') if(ch == '\t')
{ {
ncol = (col+4) & ~3; ncol = (col+3) & ~4;
if( col < ncol) if( col < ncol)
{ {
glyph_index = FT_Get_Char_Index( font->face, ansi2utf32(' ') ); glyph_index = FT_Get_Char_Index( font->face, ansi2utf32(' ') );
@ -127,7 +96,7 @@ int draw_text_ext(bitmap_t *winbitmap, font_t *font, char *text, int len, rect_t
x += delta.x ; x += delta.x ;
} }
if( x + (font->glyph[ch]->advance.x >> 10) > w) if( x + (font->glyph[ch]->advance.x >> 10) >= xend)
break; break;
x += font->glyph[ch]->advance.x >> 10; x += font->glyph[ch]->advance.x >> 10;
@ -147,15 +116,30 @@ int draw_text_ext(bitmap_t *winbitmap, font_t *font, char *text, int len, rect_t
x += delta.x ; x += delta.x ;
} }
if( x + (font->glyph[ch]->advance.x >> 10) > w) // if( x + (font->glyph[ch]->advance.x >> 10) >= xend)
// break;
if( x >= xend)
break; break;
glyph = (FT_BitmapGlyph)font->glyph[ch]; glyph = (FT_BitmapGlyph)font->glyph[ch];
my_draw_bitmap(winbitmap, &glyph->bitmap, (x >> 6) + glyph->left, if(glyph != NULL)
y - glyph->top, color); {
rect_t rc_dst;
rc_dst.l = (x >> 6) + glyph->left;
rc_dst.t = y - glyph->top;
rc_dst.r = rc_dst.l + glyph->bitmap.width;
if(rc_dst.r > (xend >> 6))
rc_dst.r = xend >> 6;
rc_dst.b = rc_dst.t + glyph->bitmap.rows;
// printf("char: %c ", ch);
px_draw_glyph(ctx, glyph->bitmap.buffer, glyph->bitmap.pitch, &rc_dst, color);
x += font->glyph[ch]->advance.x >> 10; x += font->glyph[ch]->advance.x >> 10;
};
previous = glyph_index; previous = glyph_index;
}; };
@ -180,7 +164,6 @@ int init_fontlib()
// err = FT_New_Face( library, "/kolibrios/Fonts/lucon.ttf", 0, &face ); // err = FT_New_Face( library, "/kolibrios/Fonts/lucon.ttf", 0, &face );
err = FT_New_Face( library, "/kolibrios/Fonts/DroidSansMono.ttf", 0, &face ); err = FT_New_Face( library, "/kolibrios/Fonts/DroidSansMono.ttf", 0, &face );
if ( err == FT_Err_Unknown_File_Format ) if ( err == FT_Err_Unknown_File_Format )
{ {
printf("font format is unsupported\n"); printf("font format is unsupported\n");
@ -191,37 +174,33 @@ int init_fontlib()
{ {
printf("font file could not be read or broken\n"); printf("font file could not be read or broken\n");
goto done; goto done;
} }
def_face = face; def_face = face;
err = FT_New_Face( library, "/kolibrios/Fonts/Symbols.ttf", 0, &face );
if ( err == FT_Err_Unknown_File_Format )
{
printf("font format is unsupported\n");
goto done;
}
else if ( err )
{
printf("font file could not be read or broken\n");
goto done;
}
sym_face = face;
sym_font = create_font(sym_face, 14);
done: done:
return err; return err;
}; };
unsigned int ansi2utf32(unsigned char ch)
{
if(ch < 0x80)
return ch;
if(ch < 0xB0)
return 0x410-0x80 + ch;
if(ch < 0xE0)
return 0;
if(ch < 0xF0)
return 0x440-0xE0 + ch;
if(ch == 0xF0)
return 0x401;
else if(ch==0xF1)
return 0x451;
else return 0;
}
font_t *create_font(FT_Face xface, int size) font_t *create_font(FT_Face xface, int size)
@ -236,7 +215,7 @@ font_t *create_font(FT_Face xface, int size)
memset(font, 0, sizeof(*font)); memset(font, 0, sizeof(*font));
font->face = (xface == NULL) ? def_face : xface; font->face = (xface == NULL) ? def_face : xface;
font->height = size+1; font->height = size;
err = FT_Set_Pixel_Sizes( font->face, 0, size ); err = FT_Set_Pixel_Sizes( font->face, 0, size );
@ -276,3 +255,9 @@ font_t *create_font(FT_Face xface, int size)
return font; return font;
} }
int get_font_height(font_t *font)
{
return font->height;
}

View File

@ -1,53 +1,36 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_GLYPH_H #include FT_GLYPH_H
#include <kos32sys.h> #include <kos32sys.h>
#include <pixlib2.h>
typedef struct #include "winlib.h"
{
int l;
int t;
int r;
int b;
}rect_t;
typedef struct
{
FT_Face face;
int height;
int base;
FT_Glyph glyph[256]; typedef struct tview *tview_t;
}font_t; tview_t *create_tview(ctx_t *ctx, int width, int height);
void txv_get_margins(const tview_t *txv, rect_t *margins);
typedef struct void txv_set_margins(tview_t *txv, const rect_t *margins);
{
bitmap_t bitmap;
font_t *font;
char *text;
char **line;
int lines;
int txlines;
int startline;
int endline;
int w;
int h;
}tview_t;
int init_tview(tview_t *txv, int width, int height, char *text, int size);
void txv_set_size(tview_t *txv, int txw, int txh); void txv_set_size(tview_t *txv, int txw, int txh);
void txv_set_font_size(tview_t *txv, int size); void txv_set_font_size(tview_t *txv, int size);
int txv_get_font_size(tview_t *txv);
void txv_set_text(tview_t *txv, char *text, int size);
int txv_scroll_up(tview_t *txv); int txv_scroll_up(tview_t *txv);
int txv_scroll_down(tview_t *txv); int txv_scroll_down(tview_t *txv);
int txv_page_up(tview_t *txv);
int txv_page_down(tview_t *txv);
typedef struct
{
volatile int lock;
unsigned int handle;
}mutex_t;
void* init_fontlib(); void* init_fontlib();
int draw_text_ext(bitmap_t *winbitmap, FT_Face face, char *text, int len, rect_t *rc, int color);
void draw_window(void) void draw_window(void)
{ {
@ -56,15 +39,21 @@ void draw_window(void)
EndDraw(); EndDraw();
} }
tview_t txv; tview_t *txv;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
ufile_t uf; ufile_t uf;
oskey_t key; oskey_t key;
ctx_t *ctx;
rect_t margins = {4,2,20,0};
int clw = 640; int clw = 640;
int clh = 480; int clh = 480;
__asm__ __volatile__( __asm__ __volatile__(
"int $0x40" "int $0x40"
::"a"(40), "b"(0xc0000027)); ::"a"(40), "b"(0xc0000027));
@ -77,16 +66,18 @@ int main(int argc, char *argv[])
uf.size == 0) uf.size == 0)
return 0; return 0;
init_pixlib(0); ctx = create_context(TYPE_3_BORDER_WIDTH, get_skin_height(), clw, clh);
init_fontlib(); init_fontlib();
init_tview(&txv, clw, clh, uf.data, uf.size); txv = create_tview(ctx, clw, clh);
txv_set_margins(txv, &margins);
txv_set_text(txv, uf.data, uf.size);
BeginDraw(); BeginDraw();
DrawWindow(10, 40, clw+TYPE_3_BORDER_WIDTH*2, DrawWindow(10, 40, clw+TYPE_3_BORDER_WIDTH*2,
clh+TYPE_3_BORDER_WIDTH+get_skin_height(), "Text example", 0x000000, 0x73); clh+TYPE_3_BORDER_WIDTH+get_skin_height(), "Text example", 0x000000, 0x73);
blit_bitmap(&txv.bitmap, TYPE_3_BORDER_WIDTH, get_skin_height(), txv.w, txv.h, 0, 0); show_context(ctx);
EndDraw(); EndDraw();
for (;;) for (;;)
@ -102,8 +93,14 @@ int main(int argc, char *argv[])
char proc_info[1024]; char proc_info[1024];
int winx, winy, winw, winh; int winx, winy, winw, winh;
int txw, txh; int txw, txh;
char state;
draw_window();
get_proc_info(proc_info); get_proc_info(proc_info);
state = *(char*)(proc_info+70);
if(state & (WIN_STATE_MINIMIZED|WIN_STATE_ROLLED))
continue;
winx = *(uint32_t*)(proc_info+34); winx = *(uint32_t*)(proc_info+34);
winy = *(uint32_t*)(proc_info+38); winy = *(uint32_t*)(proc_info+38);
@ -116,47 +113,56 @@ int main(int argc, char *argv[])
if( (txw != clw) || if( (txw != clw) ||
(txh != clh) ) (txh != clh) )
{ {
txv_set_size(&txv, txw, txh); resize_context(ctx, txw, txh);
txv_set_size(txv, txw, txh);
clw = txw; clw = txw;
clh = txh; clh = txh;
}; };
draw_window(); show_context(ctx);
blit_bitmap(&txv.bitmap, TYPE_3_BORDER_WIDTH, get_skin_height(), txv.w, txv.h, 0, 0);
break; break;
} }
case 2: case 2:
key = get_key(); key = get_key();
printf("key %d\n", key.code); // printf("key %d\n", key.code);
switch(key.code) switch(key.code)
{ {
case 27: case 27:
return; return 0;
case 45: case 45:
txv_set_font_size(&txv, txv.font->height-3); txv_set_font_size(txv, txv_get_font_size(txv) - 2);
blit_bitmap(&txv.bitmap, TYPE_3_BORDER_WIDTH, get_skin_height(), txv.w, txv.h, 0, 0); show_context(ctx);
break; break;
case 61: case 61:
txv_set_font_size(&txv, txv.font->height+1); txv_set_font_size(txv, txv_get_font_size(txv) + 2);
blit_bitmap(&txv.bitmap, TYPE_3_BORDER_WIDTH, get_skin_height(), txv.w, txv.h, 0, 0); show_context(ctx);
break; break;
case 177: case 177:
if( txv_scroll_up(&txv) ) if( txv_scroll_down(txv) )
blit_bitmap(&txv.bitmap, TYPE_3_BORDER_WIDTH, get_skin_height(), txv.w, txv.h, 0, 0); show_context(ctx);
break; break;
case 178: case 178:
if( txv_scroll_down(&txv) ) if( txv_scroll_up(txv) )
blit_bitmap(&txv.bitmap, TYPE_3_BORDER_WIDTH, get_skin_height(), txv.w, txv.h, 0, 0); show_context(ctx);
break;
case 183:
if( txv_page_down(txv) )
show_context(ctx);
break;
case 184:
if( txv_page_up(txv) )
show_context(ctx);
break; break;
} }
break; break;
case 3: case 3:
// button pressed; we have only one button, close // button pressed; we have only one button, close
return; return 0;
case 6: case 6:
// pos = get_mouse_pos(); // pos = get_mouse_pos();
@ -165,15 +171,15 @@ int main(int argc, char *argv[])
if( wheels & 0xFFFF) if( wheels & 0xFFFF)
{ {
int r; int r = 0;
if((short)wheels > 0) if((short)wheels > 0)
r = txv_scroll_up(&txv); r = txv_scroll_down(txv);
else else if((short)wheels < 0)
r = txv_scroll_down(&txv); r = txv_scroll_up(txv);
if( r ) if( r )
blit_bitmap(&txv.bitmap, TYPE_3_BORDER_WIDTH, get_skin_height(), txv.w, txv.h, 0, 0); show_context(ctx);
} }
} }
} }

View File

@ -0,0 +1,339 @@
#include <stdlib.h>
#include <kos32sys.h>
#include "pxdraw.h"
#include "internal.h"
ctx_t* create_context(int x, int y, int width, int height)
{
ctx_t *ctx;
ctx = malloc(sizeof(ctx_t));
if (ctx == NULL)
goto err_0;
ctx->pitch = ALIGN(width * sizeof(color_t), 16);
ctx->size = ALIGN(ctx->pitch * height, 4096);
ctx->buffer = user_alloc(ctx->size+4096);
if (ctx->buffer == NULL)
goto err_1;
ctx->x = x;
ctx->y = y;
ctx->width = width;
ctx->height = height;
ctx->rc.l = 0;
ctx->rc.t = 0;
ctx->rc.r = width;
ctx->rc.b = height;
ctx->rcu.l = 0;
ctx->rcu.t = 0;
ctx->rcu.r = ctx->width;
ctx->rcu.b = ctx->height;
ctx->dirty = 1;
__builtin_cpu_init ();
if (__builtin_cpu_supports ("sse2"))
ctx->px_rect_simd = px_rect_xmm;
else if (__builtin_cpu_supports ("mmx"))
ctx->px_rect_simd = px_rect_mmx;
else
ctx->px_rect_simd = px_rect_alu;
if (__builtin_cpu_supports ("sse2"))
ctx->px_glyph = px_glyph_sse;
else
ctx->px_glyph = px_glyph_alu;
return ctx;
err_1:
free(ctx);
err_0:
return NULL;
};
int resize_context(ctx_t *ctx, int width, int height)
{
int size;
int pitch;
pitch = ALIGN(width * sizeof(color_t), 16);
size = ALIGN(pitch * height, 4096);
if (size > ctx->size)
{
ctx->buffer = user_realloc(ctx->buffer, size); /* grow buffer */
if (ctx->buffer == NULL)
return -1;
ctx->size = size;
}
else if (size < ctx->size)
user_unmap(ctx->buffer, size, ctx->size - size); /* unmap unused pages */
ctx->width = width;
ctx->height = height;
ctx->pitch = pitch;
ctx->rc.l = 0;
ctx->rc.t = 0;
ctx->rc.r = width;
ctx->rc.b = height;
ctx->rcu.l = ctx->rcu.t = 0;
ctx->rcu.r = ctx->rcu.b = 0;
return 0;
};
void clear_context(ctx_t *ctx, color_t color)
{
size_t size;
size = ctx->pitch * ctx->height;
if (size >= 1024)
ctx->px_rect_simd(ctx->buffer, ctx->pitch, ctx->width, ctx->height, color);
else
px_rect_alu(ctx->buffer, ctx->pitch, ctx->width, ctx->height, color);
ctx->rcu.l = 0;
ctx->rcu.t = 0;
ctx->rcu.r = ctx->width;
ctx->rcu.b = ctx->height;
ctx->dirty = 1;
};
void show_context(ctx_t *ctx)
{
struct blit_call bc;
int ret;
bc.dstx = ctx->x;
bc.dsty = ctx->y;
bc.w = ctx->width;
bc.h = ctx->height;
bc.srcx = 0;
bc.srcy = 0;
bc.srcw = ctx->width;
bc.srch = ctx->height;
bc.stride = ctx->pitch;
bc.bitmap = ctx->buffer;
__asm__ __volatile__(
"int $0x40":"=a"(ret):"a"(73), "b"(0x00),
"c"(&bc):"memory");
ctx->dirty = 0;
};
void scroll_context(ctx_t *ctx, int dst_y, int src_y, int rows)
{
char *dst;
char *src;
dst = ctx->buffer + dst_y * ctx->pitch;
src = ctx->buffer + src_y * ctx->pitch;
__builtin_memmove(dst, src, rows * ctx->pitch);
ctx->dirty = 1;
}
static int clip_rect(const rect_t *clip, rect_t *rc)
{
if (rc->l > rc->r)
return 1;
if (rc->t > rc->b)
return 1;
if (rc->l < clip->l)
rc->l = clip->l;
else if (rc->l >= clip->r)
return 1;
if (rc->t < clip->t)
rc->t = clip->t;
else if (rc->t >= clip->b)
return 1;
if (rc->r < clip->l)
return 1;
else if (rc->r > clip->r)
rc->r = clip->r;
if (rc->b < clip->t)
return 1;
else if (rc->b > clip->b)
rc->b = clip->b;
if ((rc->l == rc->r) ||
(rc->t == rc->b))
return 1;
return 0;
}
int px_hline(ctx_t*ctx, int x, int y, int width, color_t color)
{
char *dst_addr;
int xr = x + width;
if(y < ctx->rc.t)
return 0;
else if(y >= ctx->rc.b)
return 0;
if(x < ctx->rc.l)
x = ctx->rc.l;
else if(x >= ctx->rc.r)
return 0;
if(xr <= ctx->rc.l)
return 0;
else if(xr > ctx->rc.r)
xr = ctx->rc.r;
dst_addr = ctx->buffer;
dst_addr+= ctx->pitch * y + x * sizeof(color_t);
__asm__ __volatile__
(" cld; rep stosl\n\t"
:: "D" (dst_addr),"c" (xr-x), "a" (color)
: "flags");
};
void px_vline(ctx_t*ctx, int x, int y, int height, color_t color)
{
char *dst_addr;
int yb = y + height;
if(x < ctx->rc.l)
return;
else if(x >= ctx->rc.r)
return;
if(y < ctx->rc.t)
y = ctx->rc.t;
else if(y >= ctx->rc.b)
return;
if(yb <= ctx->rc.t)
return;
else if(yb > ctx->rc.b)
yb = ctx->rc.b;
dst_addr = ctx->buffer;
dst_addr+= ctx->pitch * y + x * sizeof(color_t);
while(y < yb)
{
color_t *t = (color_t*)dst_addr;
*t = color;
y++;
dst_addr+= ctx->pitch;
};
};
static int do_fill_rect(ctx_t *ctx, rect_t *rc, color_t color)
{
if (!clip_rect(&ctx->rc, rc))
{
int w, h;
char *dst_addr;
w = rc->r - rc->l;
h = rc->b - rc->t;
dst_addr = ctx->buffer;
dst_addr += ctx->pitch * rc->t + rc->l * sizeof(color_t);
if (w * h >= 256)
ctx->px_rect_simd(dst_addr, ctx->pitch, w, h, color);
else
px_rect_alu(dst_addr, ctx->pitch, w, h, color);
return 1;
};
return 0;
};
void px_fill_rect(ctx_t *ctx, const rect_t *src, color_t color)
{
rect_t rc = *src;
int update;
update = do_fill_rect(ctx, &rc, color);
if(update)
{
if (rc.l < ctx->rcu.l)
ctx->rcu.l = rc.l;
if (rc.t < ctx->rcu.t)
ctx->rcu.t = rc.t;
if (rc.r > ctx->rcu.r)
ctx->rcu.r = rc.r;
if (rc.b > ctx->rcu.b)
ctx->rcu.b = rc.b;
ctx->dirty = 1;
};
}
void px_fill_region(ctx_t *ctx, const rgn_t *rgn, color_t color)
{
int update = 0;
for (int i = 0; i < rgn->num_rects; i++)
{
rect_t rc = rgn->rects[i];
update |= do_fill_rect(ctx, &rc, color);
}
if (update)
{
if (rgn->extents.l < ctx->rcu.l)
ctx->rcu.l = rgn->extents.l;
if (rgn->extents.t < ctx->rcu.t)
ctx->rcu.t = rgn->extents.t;
if (rgn->extents.r > ctx->rcu.r)
ctx->rcu.r = rgn->extents.r;
if (rgn->extents.b > ctx->rcu.b)
ctx->rcu.b = rgn->extents.b;
ctx->dirty = 1;
};
}
void px_draw_glyph(ctx_t *ctx, const void *buffer, int pitch, const rect_t *rc, color_t color)
{
rect_t rc_dst = *rc;
int srcx, srcy;
if (!clip_rect(&ctx->rc, &rc_dst))
{
int width;
int height;
unsigned char *dst = ctx->buffer;
const unsigned char *src = buffer;
width = rc_dst.r - rc_dst.l;
height = rc_dst.b - rc_dst.t;
srcx = rc_dst.l - rc->l;
srcy = rc_dst.t - rc->t;
dst += ctx->pitch * rc_dst.t + rc_dst.l * sizeof(color_t);
src += pitch * srcy + srcx;
ctx->px_glyph(dst, ctx->pitch, src, pitch, width, height, color);
if (rc_dst.l < ctx->rcu.l)
ctx->rcu.l = rc_dst.l;
if (rc_dst.t < ctx->rcu.t)
ctx->rcu.t = rc_dst.t;
if (rc_dst.r > ctx->rcu.r)
ctx->rcu.r = rc_dst.r;
if (rc_dst.b > ctx->rcu.b)
ctx->rcu.b = rc_dst.b;
ctx->dirty = 1;
};
};

View File

@ -0,0 +1,226 @@
#include <mmintrin.h>
#include <xmmintrin.h>
#include <emmintrin.h>
typedef unsigned int color_t;
void px_rect_alu(void *dst_addr, int pitch, int w, int h, color_t src_color)
{
while (h--)
{
char *tmp = dst_addr;
dst_addr = tmp + pitch;
__asm__ __volatile__(
"cld; rep stosl\n\t"
:: "D"(tmp), "a"(src_color), "c"(w)
: "flags");
};
};
void px_rect_mmx(void *dst_addr, int pitch, int w, int h, color_t src_color)
{
register __m64 color;
color = _mm_cvtsi32_si64(src_color);
color = _mm_unpacklo_pi32(color, color);
while (h--)
{
char *tmp = dst_addr;
char *end = tmp + w * sizeof(color_t);
dst_addr = tmp + pitch;
int t = (int)tmp;
if (t & 4)
{
*(color_t*)tmp = src_color;
tmp += 4;
};
while (tmp + 64 <= end)
{
__m64 *_tmp = (__m64*)tmp;
_tmp[0] = color;
_tmp[1] = color;
_tmp[2] = color;
_tmp[3] = color;
_tmp[4] = color;
_tmp[5] = color;
_tmp[6] = color;
_tmp[7] = color;
tmp += 64;
};
if (tmp + 32 <= end)
{
__m64 *_tmp = (__m64*)tmp;
_tmp[0] = color;
_tmp[1] = color;
_tmp[2] = color;
_tmp[3] = color;
tmp += 32;
};
if (tmp + 16 <= end)
{
__m64 *_tmp = (__m64*)tmp;
_tmp[0] = color;
_tmp[1] = color;
tmp += 16;
};
if (tmp + 8 <= end)
{
__m64 *_tmp = (__m64*)tmp;
_tmp[0] = color;
tmp += 8;
};
if (tmp < end)
*(color_t*)tmp = src_color;
};
_mm_empty();
};
void px_rect_xmm(void *dst_addr, int pitch, int w, int h, color_t dst_color)
{
__m128i color;
color = _mm_set_epi32(dst_color, dst_color, dst_color, dst_color);
while (h--)
{
char *tmp = dst_addr;
char *end = tmp + w * sizeof(color_t);
dst_addr = tmp + pitch;
if ((int)tmp & 4)
{
*(color_t*)tmp = dst_color;
tmp += 4;
};
if ((int)tmp & 8)
{
__m128i *_tmp = (__m128i*)tmp;
_mm_storel_epi64(_tmp, color);
tmp += 8;
};
while (tmp + 128 <= end)
{
__m128i *_tmp = (__m128i*)tmp;
_mm_store_si128(&_tmp[0], color);
_mm_store_si128(&_tmp[1], color);
_mm_store_si128(&_tmp[2], color);
_mm_store_si128(&_tmp[3], color);
_mm_store_si128(&_tmp[4], color);
_mm_store_si128(&_tmp[5], color);
_mm_store_si128(&_tmp[6], color);
_mm_store_si128(&_tmp[7], color);
tmp += 128;
};
if (tmp + 64 <= end)
{
__m128i *_tmp = (__m128i*)tmp;
_mm_store_si128(&_tmp[0], color);
_mm_store_si128(&_tmp[1], color);
_mm_store_si128(&_tmp[2], color);
_mm_store_si128(&_tmp[3], color);
tmp += 64;
};
if (tmp + 32 <= end)
{
__m128i *_tmp = (__m128i*)tmp;
_mm_store_si128(&_tmp[0], color);
_mm_store_si128(&_tmp[1], color);
tmp += 32;
};
if (tmp + 16 <= end)
{
__m128i *_tmp = (__m128i*)tmp;
_mm_store_si128(&_tmp[0], color);
tmp += 16;
};
if (tmp + 8 <= end)
{
__m128i *_tmp = (__m128i*)tmp;
_mm_storel_epi64(_tmp, color);
tmp += 8;
};
if (tmp < end)
*(color_t*)tmp = dst_color;
};
}
void px_glyph_alu(void *dst_addr, int dst_pitch,const void *src_addr, int src_pitch,
int width, int height, color_t src_color)
{
while (height-- > 0)
{
int w = width;
const unsigned char *src = src_addr;
color_t *dst = dst_addr;
dst_addr = (char*)dst + dst_pitch;
src_addr = src + src_pitch;
while (w-- > 0)
{
unsigned char a = *src++;
color_t dst_color = *(color_t*)dst;
unsigned int rb = dst_color & 0xff00ff;
unsigned int g = dst_color & 0x00ff00;
rb += ((src_color & 0xff00ff) - rb) * a >> 8;
g += ((src_color & 0x00ff00) - g) * a >> 8;
*dst++ = (src_color & 0xFF000000) | (rb & 0xff00ff) | (g & 0xff00);
};
}
}
__m64 m_4x0080 = { 0x00800080, 0x00800080 };
__m64 m_4x0101 = { 0x01010101, 0x01010101 };
__m64 m_4x00FF = { 0x00FF00FF, 0x00FF00FF };
__m64 m_zero = { 0 };
void px_glyph_sse(void *dst_addr, int dst_pitch, const void *src_addr, int src_pitch,
int width, int height, color_t src_color)
{
static __m64 m_4x0080 = { 0x00800080, 0x00800080 };
static __m64 m_4x0101 = { 0x01010101, 0x01010101 };
static __m64 m_4x00FF = { 0x00FF00FF, 0x00FF00FF };
static __m64 m_zero = { 0 };
__m64 color;
color = _mm_cvtsi32_si64(src_color);
color = _m_punpcklbw(color, m_zero);
while (height-- > 0)
{
int w = width;
const unsigned char *tmpsrc = src_addr;
color_t *tmpdst = dst_addr;
dst_addr = (char*)tmpdst + dst_pitch;
src_addr = tmpsrc + src_pitch;
while (w-- > 0)
{
__m64 m_alpha, m_1_minus_alpha;
__m64 src_alpha, dst_color;
unsigned int alpha = *tmpsrc++;
m_alpha = _mm_cvtsi32_si64((alpha << 16) | alpha);
dst_color = _mm_cvtsi32_si64(*(int*)tmpdst);
m_alpha = _mm_unpacklo_pi32(m_alpha, m_alpha);
m_1_minus_alpha = _m_psubb(m_4x00FF, m_alpha);
dst_color = _m_punpcklbw(dst_color, m_zero);
src_alpha = _m_pmullw(color, m_alpha);
dst_color = _m_pmullw(dst_color, m_1_minus_alpha);
dst_color = _m_paddw(src_alpha, dst_color);
dst_color = _m_paddw(dst_color, m_4x0080);
dst_color = _mm_mulhi_pu16(dst_color, m_4x0101);
dst_color = _mm_packs_pu16(dst_color, dst_color);
*tmpdst++ = _mm_cvtsi64_si32(dst_color);
};
}
_mm_empty();
};

View File

@ -0,0 +1,31 @@
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
struct context
{
int x;
int y;
int width;
int height;
rect_t rc;
rect_t rcu;
void *buffer;
size_t pitch;
size_t size;
int dirty;
void (*px_rect_simd)(void *dst_addr, int pitch, int w, int h, color_t dst_color);
void (*px_glyph)(void *dst_addr, int dst_pitch, const void *src_addr, int src_pitch,
int width, int height, color_t src_color);
};
void px_rect_alu(void *dst_addr, int pitch, int w, int h, color_t src_color);
void px_rect_mmx(void *dst_addr, int pitch, int w, int h, color_t src_color);
void px_rect_xmm(void *dst_addr, int pitch, int w, int h, color_t dst_color);
void px_glyph_alu(void *dst_addr, int dst_pitch,const void *src_addr,
int src_pitch, int width, int height, color_t src_color);
void px_glyph_sse(void *dst_addr, int dst_pitch, const void *src_addr,
int src_pitch, int width, int height, color_t src_color);

View File

@ -0,0 +1,46 @@
#ifndef __PXDRAW_H__
#define __PXDRAW_H__
#include <stdint.h>
#if defined __cplusplus
extern "C" {
#endif
typedef unsigned int color_t;
typedef struct context ctx_t;
typedef struct
{
int l;
int t;
int r;
int b;
}rect_t;
typedef struct
{
int num_rects;
rect_t *rects;
rect_t extents;
}rgn_t;
rgn_t* create_round_rect_rgn(int left, int top, int right, int bottom,
int ellipse_width, int ellipse_height);
void destroy_region(rgn_t *rgn);
ctx_t* create_context(int x, int y, int width, int height);
int resize_context(ctx_t *ctx, int width, int height);
void clear_context(ctx_t *ctx, color_t color);
void show_context(ctx_t *ctx);
void scroll_context(ctx_t *ctx, int dst_y, int src_y, int rows);
int px_hline(ctx_t*ctx, int x, int y, int width, color_t color);
void px_vline(ctx_t*ctx, int x, int y, int height, color_t color);
void px_fill_rect(ctx_t *ctx, const rect_t *src, color_t color);
void px_draw_glyph(ctx_t *ctx, const void *buffer, int pitch, const rect_t *rc, color_t color);
#if defined __cplusplus
}
#endif
#endif /* __PXDRAW_H__ */

View File

@ -0,0 +1,93 @@
#include <stdlib.h>
#include "pxdraw.h"
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
rgn_t* create_round_rect_rgn(int left, int top, int right, int bottom,
int ellipse_width, int ellipse_height)
{
rgn_t *obj;
rect_t *rects;
int a, b, i, x, y;
int64_t asq, bsq, dx, dy, err;
right--;
bottom--;
ellipse_width = min(right - left, abs(ellipse_width));
ellipse_height = min(bottom - top, abs(ellipse_height));
obj = malloc(sizeof(rgn_t));
if (obj == NULL)
return NULL;
obj->num_rects = ellipse_height;
obj->extents.l = left;
obj->extents.t = top;
obj->extents.r = right;
obj->extents.b = bottom;
obj->rects = rects = malloc(obj->num_rects * sizeof(rect_t));
if (rects == NULL)
{
free(obj);
return NULL;
};
/* based on an algorithm by Alois Zingl */
a = ellipse_width - 1;
b = ellipse_height - 1;
asq = (int64_t)8 * a * a;
bsq = (int64_t)8 * b * b;
dx = (int64_t)4 * b * b * (1 - a);
dy = (int64_t)4 * a * a * (1 + (b % 2));
err = dx + dy + a * a * (b % 2);
x = 0;
y = ellipse_height / 2;
rects[y].l = left;
rects[y].r = right;
while (x <= ellipse_width / 2)
{
int64_t e2 = 2 * err;
if (e2 >= dx)
{
x++;
err += dx += bsq;
}
if (e2 <= dy)
{
y++;
err += dy += asq;
rects[y].l = left + x;
rects[y].r = right - x;
}
}
for (i = 0; i < ellipse_height / 2; i++)
{
rects[i].l = rects[b - i].l;
rects[i].r = rects[b - i].r;
rects[i].t = top + i;
rects[i].b = rects[i].t + 1;
}
for (; i < ellipse_height; i++)
{
rects[i].t = bottom - ellipse_height + i;
rects[i].b = rects[i].t + 1;
}
rects[ellipse_height / 2].t = top + ellipse_height / 2; /* extend to top of rectangle */
return obj;
};
void destroy_region(rgn_t *rgn)
{
free(rgn->rects);
free(rgn);
};

View File

@ -4,7 +4,6 @@
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_GLYPH_H #include FT_GLYPH_H
#include "winlib.h" #include "winlib.h"
#include "draw2.h"
int init_fontlib(); int init_fontlib();
font_t *create_font(FT_Face face, int size); font_t *create_font(FT_Face face, int size);
@ -87,7 +86,12 @@ static void txv_redraw(tview_t *txv)
rect_t rc; rect_t rc;
int i; int i;
draw_rect(txv->ctx, 0, 0, txv->w, txv->h, 0xFFFFFFFF); rc.l = 0;
rc.t = 0;
rc.r = txv->w;
rc.b = txv->h;
px_fill_rect(txv->ctx, &rc, 0xFFFFFFFF);
rc.l = txv->margins.l; rc.l = txv->margins.l;
rc.t = txv->margins.t; rc.t = txv->margins.t;
@ -162,14 +166,14 @@ int txv_scroll_down(tview_t *txv)
dst = txv->margins.t; dst = txv->margins.t;
src = dst + txv->line_height; src = dst + txv->line_height;
rows = txv->line_height * (txv->pagesize-1); rows = txv->line_height * (txv->pagesize-1);
scroll_ctx(txv->ctx, dst, src, rows ); scroll_context(txv->ctx, dst, src, rows );
rc.l = txv->margins.l; rc.l = txv->margins.l;
rc.t = txv->margins.t + rows; rc.t = txv->margins.t + rows;
rc.r = txv->w - txv->margins.r; rc.r = txv->w - txv->margins.r;
rc.b = rc.t + txv->line_height; rc.b = rc.t + txv->line_height;
draw_rect(txv->ctx, rc.l, rc.t, rc.r - rc.l, txv->line_height, 0xFFFFFFFF); px_fill_rect(txv->ctx, &rc, 0xFFFFFFFF);
draw_text_ext(txv->ctx, txv->font, txv->line[txv->endline], draw_text_ext(txv->ctx, txv->font, txv->line[txv->endline],
txv->line[txv->endline+1]-txv->line[txv->endline], &rc, 0xFF000000); txv->line[txv->endline+1]-txv->line[txv->endline], &rc, 0xFF000000);
@ -181,7 +185,7 @@ int txv_scroll_down(tview_t *txv)
{ {
rc.t+= txv->line_height; rc.t+= txv->line_height;
rc.b+= txv->line_height; rc.b+= txv->line_height;
draw_rect(txv->ctx, rc.l, rc.t, rc.r - rc.l, txv->line_height, 0xFFFFFFFF); px_fill_rect(txv->ctx, &rc, 0xFFFFFFFF);
draw_text_ext(txv->ctx, txv->font, txv->line[txv->endline], draw_text_ext(txv->ctx, txv->font, txv->line[txv->endline],
txv->line[txv->endline+1]-txv->line[txv->endline], &rc, 0xFF000000); txv->line[txv->endline+1]-txv->line[txv->endline], &rc, 0xFF000000);
} }
@ -202,14 +206,14 @@ int txv_scroll_up(tview_t *txv)
src = txv->margins.t; src = txv->margins.t;
dst = src + txv->line_height; dst = src + txv->line_height;
scroll_ctx(txv->ctx, dst, src, rows); scroll_context(txv->ctx, dst, src, rows);
rc.l = txv->margins.l; rc.l = txv->margins.l;
rc.t = txv->margins.t; rc.t = txv->margins.t;
rc.r = txv->w - txv->margins.r; rc.r = txv->w - txv->margins.r;
rc.b = rc.t + txv->line_height; rc.b = rc.t + txv->line_height;
draw_rect(txv->ctx, rc.l, rc.t, rc.r - rc.l, txv->line_height, 0xFFFFFFFF); px_fill_rect(txv->ctx, &rc, 0xFFFFFFFF);
txv->startline--; txv->startline--;
txv->endline--; txv->endline--;

View File

@ -0,0 +1,158 @@
#include <stdio.h>
#include <string.h>
#include "winlib.h"
typedef struct
{
ctrl_t ctrl;
uint32_t state;
char *caption;
int capt_len;
}button_t;
static void button_on_draw(button_t *btn)
{
color_t color = 0xFFD7D7D7;
char t = (char)btn->ctrl.id;
rect_t rc, rci;
if(btn->ctrl.style & 1)
{
send_message(btn->ctrl.parent, MSG_OWNERDRAW, btn, 0);
return;
}
if(btn->state & bPressed)
color = 0xFFB0B0B0;
else if(btn->state & bHighlight)
color = 0xFFE7E7E7;
rc = rci = btn->ctrl.rc;
rci.l++;
rci.t++;
px_hline(btn->ctrl.ctx, rc.l, rc.t, btn->ctrl.w, 0xFF646464);
px_fill_rect(btn->ctrl.ctx, &rci, color);
px_hline(btn->ctrl.ctx, rc.l, rc.b-1, btn->ctrl.w, 0xFF646464);
px_vline(btn->ctrl.ctx, rc.l, rc.t+1, btn->ctrl.h-2, 0xFF646464);
px_vline(btn->ctrl.ctx, rc.r-1, rc.t+1, btn->ctrl.h-2, 0xFF646464);
rc.l+= 4;
rc.t+= 6;
draw_text_ext(btn->ctrl.ctx, btn->ctrl.font, btn->caption, btn->capt_len, &rc, 0xFF000000);
};
static void button_on_mouseenter(button_t *btn)
{
btn->state|= bHighlight;
send_message(&btn->ctrl, MSG_DRAW, 0, 0);
}
static void button_on_mouseleave(button_t *btn)
{
if( (ctrl_t*)btn != mouse_capture) {
btn->state &= ~bHighlight;
send_message(&btn->ctrl, MSG_DRAW, 0, 0);
};
}
static void button_on_lbuttondown(button_t *btn, int x, int y)
{
capture_mouse((ctrl_t*)btn);
btn->state|= bPressed;
send_message(&btn->ctrl, MSG_DRAW, 0, 0);
};
static void button_on_lbuttonup(button_t *btn, int x, int y)
{
int action;
action = (btn->state & bPressed) ? MSG_COMMAND : 0;
release_mouse();
if( pt_in_rect( &btn->ctrl.rc, x, y) )
btn->state = bHighlight;
else
btn->state = 0;
send_message(&btn->ctrl, MSG_DRAW, 0, 0);
if(action)
send_message(btn->ctrl.parent,MSG_COMMAND,btn->ctrl.id,(int)btn);
};
static void button_on_mousemove(button_t *btn, int x, int y)
{
int old_state;
if( !(btn->state & bHighlight))
{
btn->state|= bHighlight;
send_message(&btn->ctrl, MSG_DRAW, 0, 0);
};
if( (ctrl_t*)btn != mouse_capture)
return;
old_state = btn->state;
if( pt_in_rect(&btn->ctrl.rc, x, y) )
btn->state |= bPressed;
else
btn->state &= ~bPressed;
if( old_state ^ btn->state)
send_message(&btn->ctrl, MSG_DRAW, 0, 0);
}
int button_proc(ctrl_t *ctrl, uint32_t msg, uint32_t arg1, uint32_t arg2)
{
button_t *btn = (button_t*)ctrl;
switch( msg )
{
HANDLE_MSG(btn, MSG_DRAW, button_on_draw);
HANDLE_MSG(btn, MSG_MOUSEENTER, button_on_mouseenter);
HANDLE_MSG(btn, MSG_MOUSELEAVE, button_on_mouseleave);
HANDLE_MSG(btn, MSG_LBTNDOWN, button_on_lbuttondown);
HANDLE_MSG(btn, MSG_LBTNDBLCLK, button_on_lbuttondown);
HANDLE_MSG(btn, MSG_LBTNUP, button_on_lbuttonup);
HANDLE_MSG(btn, MSG_MOUSEMOVE, button_on_mousemove);
}
return 0;
};
ctrl_t *create_button(char *caption, uint32_t style, int id, int x, int y,
int w, int h, ctrl_t *parent)
{
button_t *btn;
int len;
if( !parent )
return NULL;
btn = create_control(sizeof(button_t), id, x, y, w, h, parent);
btn->ctrl.style = style;
btn->ctrl.handler = button_proc;
btn->state = 0;
btn->caption = caption;
if( !caption )
btn->capt_len = 0;
else
{
len = strlen(caption);
btn->capt_len = len;
if( len )
btn->caption = strdup(caption);
else
btn->caption = NULL;
}
return &btn->ctrl;
};

View File

@ -0,0 +1,109 @@
#ifndef __CONTROL_H__
#define __CONTROL_H_
#include <stdint.h>
#include <pxdraw.h>
#include "link.h"
typedef struct font font_t;
typedef struct control ctrl_t;
typedef int (handler_t)(ctrl_t*, uint32_t, uint32_t, uint32_t);
struct control
{
link_t link;
link_t child;
handler_t *handler;
ctrl_t *parent;
ctx_t *ctx;
font_t *font;
uint32_t id;
uint32_t style;
rect_t rc;
int w;
int h;
};
void *create_control(size_t size, int id, int x, int y,
int w, int h, ctrl_t *parent);
#define bPressed 2
#define bHighlight 1
ctrl_t *create_button(char *caption, uint32_t style, int id, int x, int y,
int w, int h, ctrl_t *parent);
typedef struct
{
ctrl_t ctrl;
uint32_t state;
int pix_range;
int min_range;
int max_range;
int page_size;
int thumb_pos;
rect_t tl_rect;
rect_t br_rect;
ctrl_t *btn_up;
ctrl_t *btn_down;
ctrl_t *thumb;
}scroller_t;
#define MSG_SYS_PAINT 0x001
#define MSG_SYS_KEY 0x002
#define MSG_SYS_BUTTON 0x003
#define MSG_SYS_MOUSE 0x006
#define MSG_LBTNDOWN 0x010
#define MSG_LBTNUP 0x011
#define MSG_RBTNDOWN 0x012
#define MSG_RBTNUP 0x013
#define MSG_MBTNDOWN 0x014
#define MSG_MBTNUP 0x015
#define MSG_WHEELDOWN 0x016
#define MSG_WHEELUP 0x017
#define MSG_LBTNDBLCLK 0x018
#define MSG_MOUSEMOVE 0x019
#define MSG_MOUSEENTER 0x01A
#define MSG_MOUSELEAVE 0x01B
#define MSG_CREATE 0x020
#define MSG_SIZE 0x021
#define MSG_DRAW 0x022
#define MSG_OWNERDRAW 0x023
#define MSG_POSCHANGING 0x024
#define MSG_POSCHANGE 0x025
#define MSG_COMMAND 0x030
static inline int pt_in_rect(rect_t *rc, int x, int y)
{
if( (x >= rc->l) && (x < rc->r) &&
(y >= rc->t) && (y < rc->b) )
return 1;
return 0;
};
#define send_message( ctrl, msg, arg1, arg2) \
(ctrl)->handler( (ctrl_t*)(ctrl), \
(uint32_t)(msg), (uint32_t)(arg1), (uint32_t)(arg2))
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
#endif /* __CONTROL_H_ */

View File

@ -0,0 +1,64 @@
#ifndef __LINK_H__
#define __LINK_H__
typedef struct link
{
struct link *prev;
struct link *next;
}link_t;
#define LIST_INITIALIZE(name) \
link_t name = { .prev = &name, .next = &name }
#define list_get_instance(link, type, member) \
((type *)(((u8_t *)(link)) - ((u8_t *)&(((type *)NULL)->member))))
static inline void link_initialize(link_t *link)
{
link->prev = NULL;
link->next = NULL;
}
static inline void list_initialize(link_t *head)
{
head->prev = head;
head->next = head;
}
static inline void list_append(link_t *link, link_t *head)
{
link->prev = head->prev;
link->next = head;
head->prev->next = link;
head->prev = link;
}
static inline void list_remove(link_t *link)
{
link->next->prev = link->prev;
link->prev->next = link->next;
link_initialize(link);
}
static inline int list_empty(link_t *head)
{
return head->next == head ? 1 : 0;
}
static inline void list_prepend(link_t *link, link_t *head)
{
link->next = head->next;
link->prev = head;
head->next->prev = link;
head->next = link;
}
static inline void list_insert(link_t *new, link_t *old)
{
new->prev = old->prev;
new->next = old;
new->prev->next = new;
old->prev = new;
}
#endif /* __LINK_H__ */

View File

@ -0,0 +1,615 @@
#include <stdio.h>
#include <string.h>
#include "winlib.h"
#define ID_SCROLLER_UP 0x30
#define ID_SCROLLER_DOWN 0x31
#define ID_SCROLLER_THUMB 0x32
typedef int v2si __attribute__ ((vector_size (8)));
font_t *create_font(void *face, int size);
static pos_t old_pos;
ctrl_t *mouse_capture = NULL;
void show_window(window_t *win)
{
BeginDraw();
DrawWindow(0,0,0,0,NULL,0,0x73);
if( (win->win_state != MINIMIZED) &&
(win->win_state != ROLLED) )
show_context(win->ctx);
EndDraw();
}
window_t *create_window(char *caption, int style, int x, int y,
int w, int h, handler_t handler)
{
char proc_info[1024];
window_t *win;
if(handler==NULL)
return NULL;
win = malloc(sizeof(*win));
if(win == NULL)
return NULL;
BeginDraw();
DrawWindow(x, y, w+TYPE_3_BORDER_WIDTH*2,
h+TYPE_3_BORDER_WIDTH+get_skin_height(), caption, 0x000000, 0x73);
EndDraw();
GetProcInfo(proc_info);
x = *(uint32_t*)(proc_info+34);
y = *(uint32_t*)(proc_info+38);
w = *(uint32_t*)(proc_info+42)+1;
h = *(uint32_t*)(proc_info+46)+1;
win->handler = handler;
list_initialize(&win->link);
list_initialize(&win->child);
win->rc.l = x;
win->rc.t = y;
win->rc.r = x + w;
win->rc.b = y + h;
win->w = w;
win->h = h;
win->client.l = TYPE_3_BORDER_WIDTH;
win->client.t = get_skin_height();
win->client.r = w - TYPE_3_BORDER_WIDTH;
win->client.b = h - TYPE_3_BORDER_WIDTH;
win->clw = win->client.r - win->client.l;
win->clh = win->client.b - win->client.t;
win->caption_txt = caption;
win->style = style;
win->child_over = NULL;
win->child_focus = NULL;
win->ctx = create_context(win->client.l, win->client.t, win->clw, win->clh);
clear_context(win->ctx, 0xFFFFFFFF);
win->font = create_font(NULL, 14);
send_message((ctrl_t*)win, MSG_CREATE, 0, 0);
send_message((ctrl_t*)win, MSG_DRAW, 0, 0);
ctrl_t *child;
child = (ctrl_t*)win->child.next;
while( &child->link != &win->child)
{
send_message(child, MSG_DRAW, 0, 0);
child = (ctrl_t*)child->link.next;
};
show_window(win);
return win;
};
void handle_sys_paint(window_t *win)
{
char proc_info[1024];
int winx, winy, winw, winh;
uint8_t state;
GetProcInfo(proc_info);
winx = *(uint32_t*)(proc_info+34);
winy = *(uint32_t*)(proc_info+38);
winw = *(uint32_t*)(proc_info+42)+1;
winh = *(uint32_t*)(proc_info+46)+1;
state = *(uint8_t*)(proc_info+70);
if(state & 2)
{
win->win_state = MINIMIZED;
return;
}
else if(state & 4)
{
win->win_state = ROLLED;
show_window(win);
return;
};
if(state & 1)
state = MAXIMIZED;
else
state = NORMAL;
if( (win->w != winw) ||
(win->h != winh) )
{
ctrl_t *child;
win->client.l = TYPE_3_BORDER_WIDTH;
win->client.t = get_skin_height();
win->client.r = winw - TYPE_3_BORDER_WIDTH;
win->client.b = winh - TYPE_3_BORDER_WIDTH;
win->clw = win->client.r - win->client.l;
win->clh = win->client.b - win->client.t;
resize_context(win->ctx, win->clw, win->clh);
clear_context(win->ctx, 0xFFFFFFFF);
send_message((ctrl_t*)win, MSG_SIZE, 0, 0);
send_message((ctrl_t*)win, MSG_DRAW, 0, 0);
child = (ctrl_t*)win->child.next;
while( &child->link != &win->child)
{
send_message(child, MSG_DRAW, 0, 0);
child = (ctrl_t*)child->link.next;
};
}
win->rc.l = winx;
win->rc.t = winy;
win->rc.r = winx + winw;
win->rc.b = winy + winh;
win->w = winw;
win->h = winh;
win->win_state = state;
show_window(win);
};
ctrl_t *get_child(ctrl_t *ctrl, int x, int y)
{
ctrl_t *child = NULL;
ctrl_t *tmp = (ctrl_t*)ctrl->child.next;
while( &tmp->link != &ctrl->child )
{
if(pt_in_rect(&tmp->rc, x, y))
{
child = get_child(tmp, x, y);
return child == NULL ? tmp : child;
};
tmp = (ctrl_t*)tmp->link.next;
};
return child;
};
int send_mouse_message(window_t *win, uint32_t msg)
{
ctrl_t *child;
if(mouse_capture)
return send_message(mouse_capture, msg, 0, old_pos.val);
child = get_child((ctrl_t*)win, old_pos.x, old_pos.y);
if(msg == MSG_MOUSEMOVE)
{
if( win->child_over )
{
if(child == win->child_over)
send_message(child, MSG_MOUSEMOVE, 0, old_pos.val);
else
send_message(win->child_over, MSG_MOUSELEAVE, 0, old_pos.val);
}
else if( child )
send_message(child, MSG_MOUSEENTER, 0, old_pos.val);
win->child_over = child;
};
if( child )
return send_message(child, msg, 0, old_pos.val);
if(pt_in_rect(&win->client, old_pos.x, old_pos.y))
return send_message((ctrl_t*)win, msg, 0, old_pos.val);
};
#define DBG(x)
static void handle_sys_mouse(window_t *win)
{
static uint32_t mouse_click_time;
static int mouse_action;
static int old_buttons;
int buttons;
uint32_t wheels;
uint32_t click_time;
int action;
pos_t pos;
mouse_action = 0;
pos = get_mouse_pos(POS_WINDOW);
if(pos.val != old_pos.val)
{
mouse_action = 0x80000000;
old_pos = pos;
};
// printf("pos x%d y%d\n", pos.x, pos.y);
buttons = get_mouse_buttons();
wheels = get_mouse_wheels();
// if( wheels & 0xFFFF){
// wheels = (short)wheels>0 ? MSG_WHEELDOWN : MSG_WHEELUP;
// send_mouse_message(win, wheels);
// }
if((action = (buttons ^ old_buttons))!=0)
{
mouse_action|= action<<3;
mouse_action|= buttons & ~old_buttons;
}
old_buttons = buttons;
if(mouse_action & 0x80000000) {
DBG("mouse move \n\r");
send_mouse_message(win, MSG_MOUSEMOVE);
};
if(mouse_action & 0x09)
{
if((mouse_action & 0x09)==0x09)
{
// printf("left button down x= %d y= %d\n\r", old_x.x, old_x.y);
click_time = get_tick_count();
if(click_time < mouse_click_time+35) {
mouse_click_time = click_time;
send_mouse_message(win,MSG_LBTNDBLCLK);
}
else {
mouse_click_time = click_time;
send_mouse_message(win,MSG_LBTNDOWN);
};
}
else {
// printf("left button up \n\r");
send_mouse_message(win,MSG_LBTNUP);
}
};
if(mouse_action & 0x12)
{
if((mouse_action & 0x12)==0x12) {
DBG("right button down \n\r");
send_mouse_message(win,MSG_RBTNDOWN);
}
else {
DBG("right button up \n\r");
send_mouse_message(win,MSG_RBTNUP);
};
};
if(mouse_action & 0x24)
{
if((mouse_action & 0x24)==0x24){
DBG("middle button down \n\r");
send_mouse_message(win,MSG_MBTNDOWN);
}
else {
DBG("middle button up \n\r");
send_mouse_message(win,MSG_MBTNUP);
};
};
};
int handle_system_events(window_t *win)
{
oskey_t key;
for (;;)
{
switch (get_os_event())
{
case MSG_SYS_PAINT:
handle_sys_paint(win);
break;
case MSG_SYS_KEY:
key = get_key();
printf("key %d\n", key.code);
break;
case MSG_SYS_BUTTON:
// button pressed; we have only one button, close
return 0;
case MSG_SYS_MOUSE:
handle_sys_mouse(win);
break;
};
if( (win->win_state != MINIMIZED) &&
(win->win_state != ROLLED) )
show_context(win->ctx);
}
return 0;
}
void *create_control(size_t size, int id, int x, int y,
int w, int h, ctrl_t *parent)
{
ctrl_t *ctrl;
if( !parent )
return NULL;
ctrl = (ctrl_t*)malloc(size);
link_initialize(&ctrl->link);
list_initialize(&ctrl->child);
ctrl->parent = parent;
ctrl->ctx = parent->ctx;
ctrl->font = parent->font;
ctrl->id = id;
ctrl->rc.l = x;
ctrl->rc.t = y ;
ctrl->rc.r = x + w;
ctrl->rc.b = y + h;
ctrl->w = w;
ctrl->h = h;
list_append(&ctrl->link, &parent->child);
return ctrl;
};
int move_ctrl(ctrl_t *ctrl, int x, int y, int w, int h)
{
rect_t rc;
rc.l = x;
rc.t = y;
rc.r = w;
rc.b = h;
send_message(ctrl, MSG_POSCHANGING, 0, &rc);
ctrl->rc.l = rc.l;
ctrl->rc.t = rc.t;
ctrl->rc.r = rc.l + rc.r;
ctrl->rc.b = rc.t + rc.b;
ctrl->w = rc.r;
ctrl->h = rc.b;
send_message(ctrl, MSG_POSCHANGE, 0, &rc);
return 1;
};
/*
*
*
*
*
*
*
*
*
*/
int def_ctrl_proc(ctrl_t *ctrl, uint32_t msg, uint32_t arg1, uint32_t arg2)
{
switch( msg )
{
};
return 0;
}
/*
*
*
*
*
*
*
*
*
*/
static void scroller_on_draw(scroller_t *scrl)
{
if(scrl->btn_up)
send_message((ctrl_t*)scrl->btn_up, MSG_DRAW, 0, 0);
if(scrl->btn_down)
send_message((ctrl_t*)scrl->btn_down, MSG_DRAW, 0, 0);
if(scrl->thumb)
send_message((ctrl_t*)scrl->thumb, MSG_DRAW, 0, 0);
if(scrl->tl_rect.t != scrl->tl_rect.b)
px_fill_rect(scrl->ctrl.ctx, &scrl->tl_rect, 0xFFE1D8D0);
if(scrl->br_rect.t != scrl->br_rect.b)
px_fill_rect(scrl->ctrl.ctx, &scrl->br_rect, 0xFFE1D8D0);
}
static void scroller_on_ownerdraw(scroller_t *scrl, ctrl_t *child)
{
typedef struct
{
ctrl_t ctrl;
uint32_t state;
char *caption;
int capt_len;
}button_t;
button_t *btn;
color_t color = 0xFFD7D7D7;
char t = (char)child->id;
rect_t rc;
switch(child->id)
{
case ID_SCROLLER_UP:
case ID_SCROLLER_DOWN:
btn = (button_t*)child;
if(btn->state & bPressed)
color = 0xFFB0B0B0;
else if(btn->state & bHighlight)
color = 0xFFE7E7E7;
rc = btn->ctrl.rc;
px_fill_rect(btn->ctrl.ctx, &rc, color);
rc.l+= 3;
rc.t+= 5;
draw_text_ext(btn->ctrl.ctx, sym_font, &t, 1, &rc, 0xFF000000);
break;
case ID_SCROLLER_THUMB:
btn = (button_t*)child;
color = 0xFFB0B0B0;
if(btn->state & bPressed)
color = 0xFF707070;
else if(btn->state & bHighlight)
color = 0xFF909090;
rc = btn->ctrl.rc;
px_fill_rect(btn->ctrl.ctx, &rc, color);
}
};
static void scroller_update_layout(scroller_t *scrl)
{
// th_size = scrl->pix_range*scrl->page_size/
// (scrl->max_range-scrl->min_range);
// if(th_size > scrl->pix_range)
// th_size = scrl->pix_range;
scrl->tl_rect.l = scrl->ctrl.rc.l;
scrl->br_rect.l = scrl->ctrl.rc.l;
scrl->tl_rect.r = scrl->ctrl.rc.r;
scrl->br_rect.r = scrl->ctrl.rc.r;
scrl->tl_rect.t = scrl->btn_up->rc.b;
scrl->tl_rect.b = scrl->thumb->rc.t;
scrl->br_rect.t = scrl->thumb->rc.b;
scrl->br_rect.b = scrl->btn_down->rc.t;
scrl->pix_range = scrl->ctrl.h - 40 - 20;
};
static void scroller_on_poschange(scroller_t *scrl, rect_t *pos)
{
move_ctrl(scrl->btn_up, pos->l, pos->t, pos->r, pos->r);
move_ctrl(scrl->btn_down, pos->l, pos->t+pos->b-pos->r, pos->r, pos->r);
move_ctrl(scrl->thumb, pos->l, pos->t+pos->r, pos->r, pos->r);
scroller_update_layout(scrl);
scroller_on_draw(scrl);
};
static void scroller_on_command(scroller_t *ctrl, int id, ctrl_t *child, int notify)
{
scroller_t *scrl = (scroller_t*)ctrl;
int thumb_pos = scrl->thumb_pos;
switch(id)
{
case ID_SCROLLER_UP:
if(scrl->thumb_pos > scrl->min_range)
scrl->thumb_pos--;
printf("scroll up\n");
break;
case ID_SCROLLER_DOWN:
if(scrl->thumb_pos < scrl->max_range)
scrl->thumb_pos++;
printf("scroll down\n");
break;
};
if(thumb_pos != scrl->thumb_pos)
{
rect_t rc = scrl->thumb->rc;
int offset = scrl->pix_range*scrl->thumb_pos;
offset /= scrl->max_range - scrl->min_range;
rc.t = scrl->ctrl.rc.t + scrl->btn_up->h + offset;
rc.r = scrl->thumb->w;
rc.b = scrl->thumb->h;
move_ctrl(scrl->thumb, rc.l, rc.t, rc.r, rc.b);
scroller_update_layout(scrl);
scroller_on_draw(scrl);
}
}
int scroller_proc(ctrl_t *ctrl, uint32_t msg, uint32_t arg1, uint32_t arg2)
{
scroller_t *scrl = (scroller_t*)ctrl;
switch( msg )
{
HANDLE_MSG(scrl, MSG_DRAW, scroller_on_draw);
HANDLE_MSG(scrl, MSG_COMMAND, scroller_on_command);
HANDLE_MSG(scrl, MSG_OWNERDRAW, scroller_on_ownerdraw);
HANDLE_MSG(scrl, MSG_POSCHANGE, scroller_on_poschange);
};
return 0;
};
scroller_t *create_scroller(uint32_t style, int id, int x, int y,
int w, int h, ctrl_t *parent)
{
scroller_t *scrl;
if( !parent )
return NULL;
scrl = create_control(sizeof(scroller_t), id, x, y, w, h, parent);
scrl->ctrl.handler = scroller_proc;
scrl->min_range = 0;
scrl->max_range = 100;
scrl->thumb_pos = 0;
scrl->page_size = 1;
scrl->btn_up = create_button(NULL, 1, ID_SCROLLER_UP, x, y, w, w, (ctrl_t*)scrl);
scrl->btn_down = create_button(NULL, 1, ID_SCROLLER_DOWN, x, y+h-w, w, w, (ctrl_t*)scrl);
scrl->thumb = create_button(NULL, 1, ID_SCROLLER_THUMB, x, w, w, w, (ctrl_t*)scrl);
scroller_update_layout(scrl);
return scrl;
};

View File

@ -0,0 +1,124 @@
#ifndef __WINLIB_H__
#define __WINLIB_H__
#include <stdlib.h>
#include <kos32sys.h>
#include "control.h"
enum win_state{
NORMAL, MINIMIZED, ROLLED, MAXIMIZED, FULLSCREEN
};
typedef struct
{
link_t link;
link_t child;
handler_t *handler;
ctrl_t *parent;
ctx_t *ctx;
font_t *font;
uint32_t id;
uint32_t style;
rect_t rc;
int w;
int h;
rect_t saved;
rect_t client;
int clw;
int clh;
char *caption_txt;
ctrl_t *child_over;
ctrl_t *child_focus;
enum win_state win_state;
enum win_state saved_state;
}window_t;
#define HANDLE_MSG(ctrl, message, fn) \
case (message): return HANDLE_##message((ctrl), (arg1), (arg2), (fn))
/* void ctrl_on_draw(ctrl_t *ctrl) */
#define HANDLE_MSG_DRAW(ctrl, arg1, arg2, fn) \
((fn)(ctrl),0)
/* void ctrl_on_ownerdraw(ctrl_t *ctrl, ctrl_t *child) */
#define HANDLE_MSG_OWNERDRAW(ctrl, arg1, arg2, fn) \
((fn)((ctrl),((ctrl_t*)arg1)),0)
/* void ctrl_on_poschanging(ctrl_t *ctrl, rect_t *pos) */
#define HANDLE_MSG_POSCHANGING(ctrl, arg1, arg2, fn) \
((fn)((ctrl),((rect_t*)arg2)),0)
/* void ctrl_on_poschange(ctrl_t *ctrl, rect_t *pos) */
#define HANDLE_MSG_POSCHANGE(ctrl, arg1, arg2, fn) \
((fn)((ctrl),((rect_t*)arg2)),0)
/* void ctrl_on_mouseenter(ctrl_t *ctrl) */
#define HANDLE_MSG_MOUSEENTER(ctrl, arg1, arg2, fn) \
((fn)(ctrl),0)
/* void ctrl_on_mouseleave(ctrl_t *ctrl) */
#define HANDLE_MSG_MOUSELEAVE(ctrl, arg1, arg2, fn) \
((fn)(ctrl),0)
/* void ctrl_on_lbuttondown(ctrl_t *ctrl, int x, int y) */
#define HANDLE_MSG_LBTNDOWN(ctrl, arg1, arg2, fn) \
((fn)((ctrl), ((pos_t)arg2).x, ((pos_t)arg2).y), 0L)
#define HANDLE_MSG_LBTNDBLCLK(ctrl, arg1, arg2, fn) \
((fn)((ctrl), ((pos_t)arg2).x, ((pos_t)arg2).y), 0L)
/* void ctrl_on_lbuttonup(ctrl_t *ctrl, int x, int y) */
#define HANDLE_MSG_LBTNUP(ctrl, arg1, arg2, fn) \
((fn)((ctrl), ((pos_t)arg2).x, ((pos_t)arg2).y), 0L)
/* void ctrl_on_mousemove(ctrl_t *ctrl, int x, int y) */
#define HANDLE_MSG_MOUSEMOVE(ctrl, arg1, arg2, fn) \
((fn)((ctrl), ((pos_t)arg2).x, ((pos_t)arg2).y), 0L)
/* void ctrl_on_command(ctrl_t *ctrl, int id, ctrl_t *child, int notify) */
#define HANDLE_MSG_COMMAND(ctrl,arg1,arg2,fn) \
((fn)((ctrl),(int)(arg1 & 0xFFFF),(ctrl_t*)(arg2),(int)(arg1>>16)),0)
window_t *create_window(char *caption, int style, int x, int y,
int w, int h, handler_t handler);
int handle_system_events(window_t *win);
void show_window(window_t *win);
extern ctrl_t *mouse_capture;
static inline ctrl_t *capture_mouse(ctrl_t *newm)
{
ctrl_t *old = mouse_capture;
mouse_capture = newm;
__asm__ __volatile__(
"int $0x40"
::"a"(40), "b"(0x80000027));
return old;
}
static void release_mouse(void)
{
mouse_capture = NULL;
__asm__ __volatile__(
"int $0x40"
::"a"(40), "b"(0xC0000027));
}
extern font_t *sym_font;
int draw_text_ext(ctx_t *ctx, font_t *font, char *text, int len, rect_t *rc, color_t color);
#endif /* __WINLIB_H__ */