📄 platgtk.cxx.svn-base
字号:
if (characterSet != characterSet_) {
characterSet = characterSet_;
conv.Open("UTF-8", CharacterSetID(characterSet), false);
}
}
#endif
SurfaceImpl::SurfaceImpl() : et(singleByte), drawable(0), gc(0), ppixmap(0),
x(0), y(0), inited(false), createdGC(false)
#ifdef USE_PANGO
, pcontext(0), layout(0), characterSet(-1)
#endif
{
}
SurfaceImpl::~SurfaceImpl() {
Release();
}
void SurfaceImpl::Release() {
et = singleByte;
drawable = 0;
if (createdGC) {
createdGC = false;
gdk_gc_unref(gc);
}
gc = 0;
if (ppixmap)
gdk_pixmap_unref(ppixmap);
ppixmap = 0;
#ifdef USE_PANGO
if (layout)
g_object_unref(layout);
layout = 0;
if (pcontext)
g_object_unref(pcontext);
pcontext = 0;
conv.Close();
characterSet = -1;
#endif
x = 0;
y = 0;
inited = false;
createdGC = false;
}
bool SurfaceImpl::Initialised() {
return inited;
}
// The WindowID argument is only used for Pango builds
#ifdef USE_PANGO
#define WID_NAME wid
#else
#define WID_NAME
#endif
void SurfaceImpl::Init(WindowID WID_NAME) {
Release();
#ifdef USE_PANGO
PLATFORM_ASSERT(wid);
pcontext = gtk_widget_create_pango_context(PWidget(wid));
PLATFORM_ASSERT(pcontext);
layout = pango_layout_new(pcontext);
PLATFORM_ASSERT(layout);
#endif
inited = true;
}
void SurfaceImpl::Init(SurfaceID sid, WindowID WID_NAME) {
PLATFORM_ASSERT(sid);
GdkDrawable *drawable_ = reinterpret_cast<GdkDrawable *>(sid);
Release();
#ifdef USE_PANGO
PLATFORM_ASSERT(wid);
pcontext = gtk_widget_create_pango_context(PWidget(wid));
layout = pango_layout_new(pcontext);
#endif
drawable = drawable_;
gc = gdk_gc_new(drawable_);
// Ask for lines that do not paint the last pixel so is like Win32
gdk_gc_set_line_attributes(gc, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
createdGC = true;
inited = true;
}
void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID WID_NAME) {
PLATFORM_ASSERT(surface_);
Release();
SurfaceImpl *surfImpl = static_cast<SurfaceImpl *>(surface_);
PLATFORM_ASSERT(surfImpl->drawable);
#ifdef USE_PANGO
PLATFORM_ASSERT(wid);
pcontext = gtk_widget_create_pango_context(PWidget(wid));
PLATFORM_ASSERT(pcontext);
layout = pango_layout_new(pcontext);
PLATFORM_ASSERT(layout);
#endif
if (height > 0 && width > 0)
ppixmap = gdk_pixmap_new(surfImpl->drawable, width, height, -1);
drawable = ppixmap;
gc = gdk_gc_new(surfImpl->drawable);
// Ask for lines that do not paint the last pixel so is like Win32
gdk_gc_set_line_attributes(gc, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
createdGC = true;
inited = true;
}
void SurfaceImpl::PenColour(ColourAllocated fore) {
if (gc) {
GdkColor co;
co.pixel = fore.AsLong();
gdk_gc_set_foreground(gc, &co);
}
}
int SurfaceImpl::LogPixelsY() {
return 72;
}
int SurfaceImpl::DeviceHeightFont(int points) {
int logPix = LogPixelsY();
return (points * logPix + logPix / 2) / 72;
}
void SurfaceImpl::MoveTo(int x_, int y_) {
x = x_;
y = y_;
}
void SurfaceImpl::LineTo(int x_, int y_) {
if (drawable && gc) {
gdk_draw_line(drawable, gc,
x, y,
x_, y_);
}
x = x_;
y = y_;
}
void SurfaceImpl::Polygon(Point *pts, int npts, ColourAllocated fore,
ColourAllocated back) {
GdkPoint gpts[20];
if (npts < static_cast<int>((sizeof(gpts) / sizeof(gpts[0])))) {
for (int i = 0;i < npts;i++) {
gpts[i].x = pts[i].x;
gpts[i].y = pts[i].y;
}
PenColour(back);
gdk_draw_polygon(drawable, gc, 1, gpts, npts);
PenColour(fore);
gdk_draw_polygon(drawable, gc, 0, gpts, npts);
}
}
void SurfaceImpl::RectangleDraw(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
if (gc && drawable) {
PenColour(back);
gdk_draw_rectangle(drawable, gc, 1,
rc.left + 1, rc.top + 1,
rc.right - rc.left - 2, rc.bottom - rc.top - 2);
PenColour(fore);
// The subtraction of 1 off the width and height here shouldn't be needed but
// otherwise a different rectangle is drawn than would be done if the fill parameter == 1
gdk_draw_rectangle(drawable, gc, 0,
rc.left, rc.top,
rc.right - rc.left - 1, rc.bottom - rc.top - 1);
}
}
void SurfaceImpl::FillRectangle(PRectangle rc, ColourAllocated back) {
PenColour(back);
if (drawable && (rc.left < maxCoordinate)) { // Protect against out of range
gdk_draw_rectangle(drawable, gc, 1,
rc.left, rc.top,
rc.right - rc.left, rc.bottom - rc.top);
}
}
void SurfaceImpl::FillRectangle(PRectangle rc, Surface &surfacePattern) {
if (static_cast<SurfaceImpl &>(surfacePattern).drawable) {
// Tile pattern over rectangle
// Currently assumes 8x8 pattern
int widthPat = 8;
int heightPat = 8;
for (int xTile = rc.left; xTile < rc.right; xTile += widthPat) {
int widthx = (xTile + widthPat > rc.right) ? rc.right - xTile : widthPat;
for (int yTile = rc.top; yTile < rc.bottom; yTile += heightPat) {
int heighty = (yTile + heightPat > rc.bottom) ? rc.bottom - yTile : heightPat;
gdk_draw_pixmap(drawable,
gc,
static_cast<SurfaceImpl &>(surfacePattern).drawable,
0, 0,
xTile, yTile,
widthx, heighty);
}
}
} else {
// Something is wrong so try to show anyway
// Shows up black because colour not allocated
FillRectangle(rc, ColourAllocated(0));
}
}
void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
if (((rc.right - rc.left) > 4) && ((rc.bottom - rc.top) > 4)) {
// Approximate a round rect with some cut off corners
Point pts[] = {
Point(rc.left + 2, rc.top),
Point(rc.right - 2, rc.top),
Point(rc.right, rc.top + 2),
Point(rc.right, rc.bottom - 2),
Point(rc.right - 2, rc.bottom),
Point(rc.left + 2, rc.bottom),
Point(rc.left, rc.bottom - 2),
Point(rc.left, rc.top + 2),
};
Polygon(pts, sizeof(pts) / sizeof(pts[0]), fore, back);
} else {
RectangleDraw(rc, fore, back);
}
}
#if GTK_MAJOR_VERSION >= 2
// Plot a point into a guint32 buffer symetrically to all 4 qudrants
static void AllFour(guint32 *pixels, int stride, int width, int height, int x, int y, guint32 val) {
pixels[y*stride+x] = val;
pixels[y*stride+width-1-x] = val;
pixels[(height-1-y)*stride+x] = val;
pixels[(height-1-y)*stride+width-1-x] = val;
}
static unsigned int GetRValue(unsigned int co) {
return (co >> 16) & 0xff;
}
static unsigned int GetGValue(unsigned int co) {
return (co >> 8) & 0xff;
}
static unsigned int GetBValue(unsigned int co) {
return co & 0xff;
}
#endif
#if GTK_MAJOR_VERSION < 2
void SurfaceImpl::AlphaRectangle(PRectangle rc, int , ColourAllocated , int , ColourAllocated outline, int , int ) {
if (gc && drawable) {
// Can't use GdkPixbuf on GTK+ 1.x, so draw an outline rather than use alpha.
PenColour(outline);
gdk_draw_rectangle(drawable, gc, 0,
rc.left, rc.top,
rc.right - rc.left - 1, rc.bottom - rc.top - 1);
}
}
#else
void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourAllocated fill, int alphaFill,
ColourAllocated outline, int alphaOutline, int flags) {
if (gc && drawable) {
int width = rc.Width();
int height = rc.Height();
// Ensure not distorted too much by corners when small
cornerSize = Platform::Minimum(cornerSize, (Platform::Minimum(width, height) / 2) - 2);
// Make a 32 bit deep pixbuf with alpha
GdkPixbuf *pixalpha = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
guint8 pixVal[4] = {0};
guint32 valEmpty = *(reinterpret_cast<guint32 *>(pixVal));
pixVal[0] = GetRValue(fill.AsLong());
pixVal[1] = GetGValue(fill.AsLong());
pixVal[2] = GetBValue(fill.AsLong());
pixVal[3] = alphaFill;
guint32 valFill = *(reinterpret_cast<guint32 *>(pixVal));
pixVal[0] = GetRValue(outline.AsLong());
pixVal[1] = GetGValue(outline.AsLong());
pixVal[2] = GetBValue(outline.AsLong());
pixVal[3] = alphaOutline;
guint32 valOutline = *(reinterpret_cast<guint32 *>(pixVal));
guint32 *pixels = reinterpret_cast<guint32 *>(gdk_pixbuf_get_pixels(pixalpha));
int stride = gdk_pixbuf_get_rowstride(pixalpha) / 4;
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
if ((x==0) || (x==width-1) || (y == 0) || (y == height-1)) {
pixels[y*stride+x] = valOutline;
} else {
pixels[y*stride+x] = valFill;
}
}
}
for (int c=0;c<cornerSize; c++) {
for (int x=0;x<c+1; x++) {
AllFour(pixels, stride, width, height, x, c-x, valEmpty);
}
}
for (int x=1;x<cornerSize; x++) {
AllFour(pixels, stride, width, height, x, cornerSize-x, valOutline);
}
// Draw with alpha
gdk_draw_pixbuf(drawable, gc, pixalpha,
0,0, rc.left,rc.top, width,height, GDK_RGB_DITHER_NORMAL, 0, 0);
g_object_unref(pixalpha);
}
}
#endif
void SurfaceImpl::Ellipse(PRectangle rc, ColourAllocated fore, ColourAllocated back) {
PenColour(back);
gdk_draw_arc(drawable, gc, 1,
rc.left + 1, rc.top + 1,
rc.right - rc.left - 2, rc.bottom - rc.top - 2,
0, 32767);
// The subtraction of 1 here is similar to the case for RectangleDraw
PenColour(fore);
gdk_draw_arc(drawable, gc, 0,
rc.left, rc.top,
rc.right - rc.left - 1, rc.bottom - rc.top - 1,
0, 32767);
}
void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
if (static_cast<SurfaceImpl &>(surfaceSource).drawable) {
gdk_draw_pixmap(drawable,
gc,
static_cast<SurfaceImpl &>(surfaceSource).drawable,
from.x, from.y,
rc.left, rc.top,
rc.right - rc.left, rc.bottom - rc.top);
}
}
static size_t UTF8Len(char ch) {
unsigned char uch = static_cast<unsigned char>(ch);
if (uch < 0x80)
return 1;
else if (uch < (0x80 + 0x40 + 0x20))
return 2;
else
return 3;
}
char *UTF8FromLatin1(const char *s, int &len) {
char *utfForm = new char[len*2+1];
size_t lenU = 0;
for (int i=0;i<len;i++) {
unsigned int uch = static_cast<unsigned char>(s[i]);
if (uch < 0x80) {
utfForm[lenU++] = uch;
} else {
utfForm[lenU++] = static_cast<char>(0xC0 | (uch >> 6));
utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f));
}
}
utfForm[lenU] = '\0';
len = lenU;
return utfForm;
}
#ifdef USE_PANGO
static char *UTF8FromIconv(const Converter &conv, const char *s, int &len) {
if (conv) {
char *utfForm = new char[len*3+1];
char *pin = const_cast<char *>(s);
size_t inLeft = len;
char *pout = utfForm;
size_t outLeft = len*3+1;
size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
if (conversions != ((size_t)(-1))) {
*pout = '\0';
len = pout - utfForm;
return utfForm;
}
delete []utfForm;
}
return 0;
}
// Work out how many bytes are in a character by trying to convert using iconv,
// returning the first length that succeeds.
static size_t MultiByteLenFromIconv(const Converter &conv, const char *s, size_t len) {
for (size_t lenMB=1; (lenMB<4) && (lenMB <= len); lenMB++) {
char wcForm[2];
char *pin = const_cast<char *>(s);
size_t inLeft = lenMB;
char *pout = wcForm;
size_t outLeft = 2;
size_t conversions = conv.Convert(&pin, &inLeft, &pout, &outLeft);
if (conversions != ((size_t)(-1))) {
return lenMB;
}
}
return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -