index b0ccd2285e7af84a8ffa1f8e8444a1ebfca45378..e543fc0e7023a9700a08ddf705f83f439aa8958c 100644 (file)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*)
{$INCLUDE ../shared/a_modes.inc}
+{$DEFINE FUI_TEXT_ICONS}
unit fui_gfx_gl;
interface
uses
+ {$INCLUDE ../nogl/noGLuses.inc}
SysUtils, Classes,
- GL, GLExt, SDL2,
+ SDL2,
sdlcarcass,
fui_common, fui_events;
function combineClip (constref aclip: TGxRect): TGxRect; // returns previous clip
+ // vertical scrollbar
+ procedure drawVSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
+ // horizontal scrollbar
+ procedure drawHSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
+
+ class function sbarFilled (wh: Integer; cur, min, max: Integer): Integer;
+ class function sbarPos (cxy: Integer; xy, wh: Integer; min, max: Integer): Integer;
+
+ public //HACK!
+ procedure glSetScale (ascale: Single);
+ procedure glSetTrans (ax, ay: Single);
+ procedure glSetScaleTrans (ascale, ax, ay: Single);
+
public
property active: Boolean read mActive;
property color: TGxRGBA read mColor write setColor;
// set active context; `ctx` can be `nil`
procedure gxSetContext (ctx: TGxContext; ascale: Single=1.0);
+procedure gxSetContextNoMatrix (ctx: TGxContext);
// setup 2D OpenGL mode; will be called automatically in `glInit()`
procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false);
+procedure oglSetup2DState (); // don't modify viewports and matrices
procedure oglDrawCursor ();
procedure oglDrawCursorAt (msX, msY: Integer);
+procedure fuiGfxLoadFont (const fontname: AnsiString; const fontFile: AnsiString; proportional: Boolean=false);
+procedure fuiGfxLoadFont (const fontname: AnsiString; st: TStream; proportional: Boolean=false);
+
// ////////////////////////////////////////////////////////////////////////// //
var
implementation
+uses
+ fui_wadread,
+ utils;
+
+
+// ////////////////////////////////////////////////////////////////////////// //
+// returns `false` if the color is transparent
+// returns `false` if the color is transparent
+function setupGLColor (constref clr: TGxRGBA): Boolean;
+begin
+ if (clr.a < 255) then
+ begin
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ end
+ else
+ begin
+ glDisable(GL_BLEND);
+ end;
+ glColor4ub(clr.r, clr.g, clr.b, clr.a);
+ result := (clr.a <> 0);
+end;
+
+function isScaled (): Boolean;
+var
+ mt: packed array [0..15] of GLfloat;
+begin
+ glGetFloatv(GL_MODELVIEW_MATRIX, @mt[0]);
+ result := (mt[0] <> 1.0) or (mt[1*4+1] <> 1.0);
+end;
+
// ////////////////////////////////////////////////////////////////////////// //
//TODO: OpenGL framebuffers and shaders state
// ////////////////////////////////////////////////////////////////////////// //
// set active context; `ctx` can be `nil`
-procedure gxSetContext (ctx: TGxContext; ascale: Single=1.0);
+procedure gxSetContextInternal (ctx: TGxContext; ascale: Single; domatrix: Boolean);
+var
+ mt: packed array [0..15] of GLfloat;
begin
if (savedGLState.saved) then savedGLState.restore();
begin
ctx.mActive := true;
savedGLState.save();
- oglSetup2D(fuiScrWdt, fuiScrHgt);
- glScalef(ascale, ascale, 1.0);
- ctx.mScaled := (ascale <> 1.0);
- ctx.mScale := ascale;
+ if (domatrix) then
+ begin
+ oglSetup2D(fuiScrWdt, fuiScrHgt);
+ glScalef(ascale, ascale, 1.0);
+ ctx.mScaled := (ascale <> 1.0);
+ ctx.mScale := ascale;
+ end
+ else
+ begin
+ // assume uniform scale
+ glGetFloatv(GL_MODELVIEW_MATRIX, @mt[0]);
+ ctx.mScaled := (mt[0] <> 1.0) or (mt[1*4+1] <> 1.0);
+ ctx.mScale := mt[0];
+ oglSetup2DState();
+ end;
ctx.onActivate();
end;
end;
+procedure gxSetContext (ctx: TGxContext; ascale: Single=1.0); begin gxSetContextInternal(ctx, ascale, true); end;
+procedure gxSetContextNoMatrix (ctx: TGxContext); begin gxSetContextInternal(ctx, 1, false); end;
+
+
// ////////////////////////////////////////////////////////////////////////// //
type
TScissorSave = record
// ////////////////////////////////////////////////////////////////////////// //
-{$INCLUDE fui_gfx_gl_fonts.inc}
-
type
TGxBmpFont = class(TGxFont)
private
mFontBmp: PByte;
mFontWdt: PByte;
mFreeFontWdt: Boolean;
+ mFreeFontBmp: Boolean;
protected
procedure oglCreateTexture ();
procedure oglDestroyTexture ();
+ procedure initDrawText ();
+ procedure doneDrawText ();
+ function drawCharInterim (x, y: Integer; const ch: AnsiChar): Integer; // return width (not including last empty pixel)
+ function drawCharInternal (x, y: Integer; const ch: AnsiChar): Integer; // return width (not including last empty pixel)
function drawTextInternal (x, y: Integer; const s: AnsiString): Integer; // return width (not including last empty pixel)
public
- constructor Create (const aname: AnsiString; awdt, ahgt: Integer; const afont: PByte; const awdtable: PByte=nil);
+ constructor Create (const aname: AnsiString; st: TStream; proportional: Boolean);
destructor Destroy (); override;
function charWidth (const ch: AnsiChar): Integer; override;
end;
-constructor TGxBmpFont.Create (const aname: AnsiString; awdt, ahgt: Integer; const afont: PByte; const awdtable: PByte=nil);
+constructor TGxBmpFont.Create (const aname: AnsiString; st: TStream; proportional: Boolean);
var
- c: Integer;
+ sign: packed array [0..7] of AnsiChar;
+ enc: packed array [0..16] of AnsiChar;
+ b: Byte;
+ wdt, hgt, elen: Integer;
+ ch, dy: Integer;
+ fntbwdt: Integer;
+ wrd: Word;
begin
- if (afont = nil) then raise Exception.Create('internal error in font creation');
- if (ahgt < 1) then raise Exception.Create('internal error in font creation');
- if (awdt > 0) then
+ mFreeFontBmp := true;
+ mFreeFontWdt := true;
+ mName := aname;
+ mTexId := 0;
+ // signature
+ st.ReadBuffer(sign[0], 8);
+ if (sign <> 'FUIFONT0') then raise Exception.Create('FlexUI: invalid font file signature');
+ // encoding length and width
+ st.ReadBuffer(b, 1);
+ wdt := (b and $0f)+1; // 16 is not supported
+ if (wdt = 16) then raise Exception.Create('FlexUI: 16-wdt fonts aren''t supported yet');
+ elen := ((b shr 4) and $0f);
+ if (elen = 0) then raise Exception.CreateFmt('FlexUI: invalid font encoding length: %d', [elen]);
+ // height
+ st.ReadBuffer(b, 1);
+ hgt := b;
+ if (hgt < 2) then raise Exception.CreateFmt('FlexUI: invalid font height: %d', [hgt]);
+ // encoding
+ st.ReadBuffer(enc[0], elen);
+ // check for 'cp1251' here (it can also be 'koi8')
+ if (wdt <= 8) then fntbwdt := 1 else fntbwdt := 2;
+ // shift and width table (hi nibble: left shift for proportional print; lo nibble: shifted character width for proportional print)
+ GetMem(mFontWdt, 256);
+ st.ReadBuffer(mFontWdt^, 256);
+ // font bitmap
+ GetMem(mFontBmp, (hgt*fntbwdt)*256);
+ st.ReadBuffer(mFontBmp^, (hgt*fntbwdt)*256);
+ mWidth := wdt;
+ mHeight := hgt;
+ mBaseLine := hgt-1; //FIXME
+ if (proportional) then
begin
- //if (awdtable <> nil) then raise Exception.Create('internal error in font creation');
- mFreeFontWdt := true;
- // create width table
- GetMem(mFontWdt, 256);
- for c := 0 to 255 do mFontWdt[c] := awdt-1;
+ // shift font
+ for ch := 0 to 255 do
+ begin
+ for dy := 0 to hgt-1 do
+ begin
+ if (fntbwdt = 1) then
+ begin
+ mFontBmp[ch*hgt+dy] := mFontBmp[ch*hgt+dy] shl (mFontWdt[ch] shr 4);
+ end
+ else
+ begin
+ wrd := mFontBmp[ch*(hgt*2)+(dy*2)]+256*mFontBmp[ch*(hgt*2)+(dy*2)+1];
+ wrd := wrd shl (mFontWdt[ch] shr 4);
+ mFontBmp[ch*(hgt*2)+(dy*2)+0] := (wrd and $ff);
+ mFontBmp[ch*(hgt*2)+(dy*2)+1] := ((wrd shr 16) and $ff);
+ end;
+ end;
+ end;
end
else
begin
- if (awdtable = nil) then raise Exception.Create('internal error in font creation');
- awdt := 0;
- mFontWdt := awdtable;
+ FillChar(mFontWdt^, 256, wdt);
end;
- mName := aname;
- mWidth := awdt;
- mHeight := ahgt;
- mBaseLine := ahgt-1; //FIXME
- mFontBmp := afont;
- mTexId := 0;
end;
destructor TGxBmpFont.Destroy ();
begin
+ if (mFreeFontBmp) and (mFontBmp <> nil) then FreeMem(mFontBmp);
if (mFreeFontWdt) and (mFontWdt <> nil) then FreeMem(mFontWdt);
mName := '';
mWidth := 0;
mFontBmp := nil;
mFontWdt := nil;
mFreeFontWdt := false;
+ mFreeFontBmp := false;
mTexId := 0;
inherited;
end;
procedure TGxBmpFont.oglCreateTexture ();
+const
+ TxWidth = 16*16;
+ TxHeight = 16*16;
+var
+ tex, tpp: PByte;
+ b: Byte;
+ cc: Integer;
+ x, y, dx, dy: Integer;
begin
- mTexId := createFontTexture(mFontBmp, mFontWdt, (mWidth <= 0));
+ GetMem(tex, TxWidth*TxHeight*4);
+ FillChar(tex^, TxWidth*TxHeight*4, 0);
+
+ for cc := 0 to 255 do
+ begin
+ x := (cc mod 16)*16;
+ y := (cc div 16)*16;
+ for dy := 0 to mHeight-1 do
+ begin
+ if (mWidth <= 8) then b := mFontBmp[cc*mHeight+dy] else b := mFontBmp[cc*(mHeight*2)+(dy*2)+1];
+ //if prop then b := b shl (fontwdt[cc] shr 4);
+ tpp := tex+((y+dy)*(TxWidth*4))+x*4;
+ for dx := 0 to 7 do
+ begin
+ if ((b and $80) <> 0) then
+ begin
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ end
+ else
+ begin
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ end;
+ b := (b and $7f) shl 1;
+ end;
+ if (mWidth > 8) then
+ begin
+ b := mFontBmp[cc*(mHeight*2)+(dy*2)+0];
+ for dx := 0 to 7 do
+ begin
+ if ((b and $80) <> 0) then
+ begin
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ tpp^ := 255; Inc(tpp);
+ end
+ else
+ begin
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ tpp^ := 0; Inc(tpp);
+ end;
+ b := (b and $7f) shl 1;
+ end;
+ end;
+ end;
+ end;
+
+ glGenTextures(1, @mTexId);
+ if (mTexId = 0) then raise Exception.Create('can''t create FlexUI font texture');
+
+ glBindTexture(GL_TEXTURE_2D, mTexId);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TxWidth, TxHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);
+ glFinish();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ FreeMem(tex);
end;
end;
-// return width (not including last empty pixel)
-function TGxBmpFont.drawTextInternal (x, y: Integer; const s: AnsiString): Integer;
-var
- ch: AnsiChar;
- tx, ty: Integer;
+procedure TGxBmpFont.initDrawText ();
begin
- if (Length(s) = 0) then begin result := 0; exit; end;
-
- result := -1;
-
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_NOTEQUAL, 0.0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mTexId);
+end;
- for ch in s do
- begin
- tx := (Integer(ch) mod 16)*8;
- ty := (Integer(ch) div 16)*8;
- glBegin(GL_QUADS);
- glTexCoord2f((tx+0)/128.0, (ty+0)/128.0); glVertex2i(x+0, y+0); // top-left
- glTexCoord2f((tx+8)/128.0, (ty+0)/128.0); glVertex2i(x+8, y+0); // top-right
- glTexCoord2f((tx+8)/128.0, (ty+8)/128.0); glVertex2i(x+8, y+8); // bottom-right
- glTexCoord2f((tx+0)/128.0, (ty+8)/128.0); glVertex2i(x+0, y+8); // bottom-left
- glEnd();
- x += (mFontWdt[Byte(ch)] and $0f)+1;
- result += (mFontWdt[Byte(ch)] and $0f)+1;
- end;
+procedure TGxBmpFont.doneDrawText ();
+begin
glDisable(GL_ALPHA_TEST);
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
end;
+function TGxBmpFont.drawCharInterim (x, y: Integer; const ch: AnsiChar): Integer;
+var
+ tx, ty: Integer;
+begin
+ tx := (Integer(ch) mod 16)*16;
+ ty := (Integer(ch) div 16)*16;
+ glBegin(GL_QUADS);
+ glTexCoord2f((tx+0)/256.0, (ty+0)/256.0); glVertex2i(x+0, y+0); // top-left
+ glTexCoord2f((tx+mWidth)/256.0, (ty+0)/256.0); glVertex2i(x+mWidth, y+0); // top-right
+ glTexCoord2f((tx+mWidth)/256.0, (ty+mHeight)/256.0); glVertex2i(x+mWidth, y+mHeight); // bottom-right
+ glTexCoord2f((tx+0)/256.0, (ty+mHeight)/256.0); glVertex2i(x+0, y+mHeight); // bottom-left
+ glEnd();
+ result := (mFontWdt[Byte(ch)] and $0f);
+end;
+
+
+function TGxBmpFont.drawCharInternal (x, y: Integer; const ch: AnsiChar): Integer;
+begin
+ initDrawText();
+ result := drawCharInterim(x, y, ch);
+ doneDrawText();
+end;
+
+
+function TGxBmpFont.drawTextInternal (x, y: Integer; const s: AnsiString): Integer;
+var
+ ch: AnsiChar;
+ wdt: Integer;
+begin
+ if (Length(s) = 0) then begin result := 0; exit; end;
+ result := -1;
+ initDrawText();
+ for ch in s do
+ begin
+ wdt := drawCharInterim(x, y, ch)+1;
+ x += wdt;
+ result += wdt;
+ end;
+ doneDrawText();
+end;
+
+
// ////////////////////////////////////////////////////////////////////////// //
var
fontList: array of TGxBmpFont = nil;
- defaultFontName: AnsiString = 'dos';
+ defaultFontName: AnsiString = 'win14';
function strEquCI (const s0, s1: AnsiString): Boolean;
end;
+{
procedure deleteFonts ();
var
f: Integer;
for f := 0 to High(fontList) do freeAndNil(fontList[f]);
fontList := nil;
end;
+}
-procedure createFonts ();
+procedure fuiGfxLoadFont (const fontname: AnsiString; const fontFile: AnsiString; proportional: Boolean=false);
+var
+ st: TStream;
begin
- deleteFonts();
- SetLength(fontList, 4);
- fontList[0] := TGxBmpFont.Create('dos', 8, 8, @kgiFont8[0], @kgiFont8PropWidth[0]);
- fontList[1] := TGxBmpFont.Create('dos-prop', 0, 8, @kgiFont8[0], @kgiFont8PropWidth[0]);
- fontList[2] := TGxBmpFont.Create('msx', 6, 8, @kgiFont6[0], @kgiFont6PropWidth[0]);
- fontList[3] := TGxBmpFont.Create('msx-prop', 0, 8, @kgiFont6[0], @kgiFont6PropWidth[0]);
+ if (Length(fontname) = 0) then raise Exception.Create('FlexUI: cannot load nameless font '''+fontFile+'''');
+ st := fuiOpenFile(fontFile);
+ if (st = nil) then raise Exception.Create('FlexUI: cannot load font '''+fontFile+'''');
+ try
+ fuiGfxLoadFont(fontname, st, proportional);
+ except on e: Exception do
+ begin
+ writeln('FlexUI font loadin error: ', e.message);
+ FreeAndNil(st);
+ raise Exception.Create('FlexUI: cannot load font '''+fontFile+'''');
+ end;
+ else
+ raise;
+ end;
+ FreeAndNil(st);
+end;
+
+
+procedure fuiGfxLoadFont (const fontname: AnsiString; st: TStream; proportional: Boolean=false);
+var
+ fnt: TGxBmpFont = nil;
+ f: Integer;
+begin
+ if (Length(fontname) = 0) then raise Exception.Create('FlexUI: cannot load nameless font');
+ fnt := TGxBmpFont.Create(fontname, st, proportional);
+ try
+ for f := 0 to High(fontList) do
+ begin
+ if (strEquCI(fontList[f].name, fontname)) then
+ begin
+ if (fontList[f].mTexId <> 0) then raise Exception.Create('FlexUI: cannot reload generated font named '''+fontname+'''');
+ FreeAndNil(fontList[f]);
+ fontList[f] := fnt;
+ exit;
+ end;
+ end;
+ SetLength(fontList, Length(fontList)+1);
+ fontList[High(fontList)] := fnt;
+ except
+ FreeAndNil(fnt);
+ raise;
+ end;
end;
// ////////////////////////////////////////////////////////////////////////// //
-procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false);
+procedure oglSetup2DState ();
begin
- glViewport(0, 0, winWidth, winHeight);
-
glDisable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_CULL_FACE);
glDisable(GL_ALPHA_TEST);
+ glClearColor(0, 0, 0, 0);
+ glColor4f(1, 1, 1, 1);
+end;
+
+
+procedure oglSetup2D (winWidth, winHeight: Integer; upsideDown: Boolean=false);
+begin
+ glViewport(0, 0, winWidth, winHeight);
+
+ oglSetup2DState();
+
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
-
- glClearColor(0, 0, 0, 0);
- glColor4f(1, 1, 1, 1);
end;
procedure oglDrawCursor (); begin oglDrawCursorAt(fuiMouseX, fuiMouseY); end;
-// ////////////////////////////////////////////////////////////////////////// //
-// returns `false` if the color is transparent
-// returns `false` if the color is transparent
-function setupGLColor (constref clr: TGxRGBA): Boolean;
-begin
- if (clr.a < 255) then
- begin
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- end
- else
- begin
- glDisable(GL_BLEND);
- end;
- glColor4ub(clr.r, clr.g, clr.b, clr.a);
- result := (clr.a <> 0);
-end;
-
-function mScaled (): Boolean;
-var
- mt: packed array [0..15] of Double;
-begin
- glGetDoublev(GL_MODELVIEW_MATRIX, @mt[0]);
- result := (mt[0] <> 1.0) or (mt[1*4+1] <> 1.0);
-end;
-
-
// ////////////////////////////////////////////////////////////////////////// //
constructor TGxContext.Create ();
begin
glVertex2f(x+len+0.375, y+0.375);
glEnd();
end
- else
+ else if (mScale > 1.0) then
begin
glBegin(GL_QUADS);
glVertex2i(x, y);
glVertex2i(x+len, y+1);
glVertex2i(x, y+1);
glEnd();
+ end
+ else
+ begin
+ glPointSize(1);
+ glBegin(GL_POINTS);
+ while (len > 0) do begin glVertex2i(x, y); Inc(x); Dec(len); end;
+ glEnd();
end;
end;
glVertex2f(x+0.375, y+len+0.375);
glEnd();
end
- else
+ else if (mScale > 1.0) then
begin
glBegin(GL_QUADS);
glVertex2i(x, y);
glVertex2i(x+1, y+len);
glVertex2i(x+1, y);
glEnd();
- end;
-end;
-
-
-procedure TGxContext.rect (x, y, w, h: Integer);
- procedure hlinex (x, y, len: Integer);
+ end
+ else
begin
- if (len < 1) then exit;
- glBegin(GL_QUADS);
- glVertex2i(x, y);
- glVertex2i(x+len, y);
- glVertex2i(x+len, y+1);
- glVertex2i(x, y+1);
+ glPointSize(1);
+ glBegin(GL_POINTS);
+ while (len > 0) do begin glVertex2i(x, y); Inc(y); Dec(len); end;
glEnd();
end;
+end;
- procedure vlinex (x, y, len: Integer);
- begin
- if (len < 1) then exit;
- glBegin(GL_QUADS);
- glVertex2i(x, y);
- glVertex2i(x, y+len);
- glVertex2i(x+1, y+len);
- glVertex2i(x+1, y);
- glEnd();
- end;
+procedure TGxContext.rect (x, y, w, h: Integer);
begin
if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
if (w < 0) or (h < 0) then exit;
end
else
begin
- hlinex(x, y, w);
- hlinex(x, y+h-1, w);
- vlinex(x, y+1, h-2);
- vlinex(x+w-1, y+1, h-2);
+ hline(x, y, w);
+ hline(x, y+h-1, w);
+ vline(x, y+1, h-2);
+ vline(x+w-1, y+1, h-2);
end;
end;
end;
@@ -917,7 +1139,7 @@ function TGxContext.drawChar (x, y: Integer; const ch: AnsiChar): Integer; // re
begin
result := mFont.charWidth(ch);
if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
- TGxBmpFont(mFont).drawTextInternal(x, y, ch);
+ TGxBmpFont(mFont).drawCharInternal(x, y, ch);
end;
function TGxContext.drawText (x, y: Integer; const s: AnsiString): Integer; // returns text width
end;
-function TGxContext.iconMarkWidth (ic: TMarkIcon): Integer; begin result := 11; end;
-function TGxContext.iconMarkHeight (ic: TMarkIcon): Integer; begin result := 8; end;
+function TGxContext.iconMarkWidth (ic: TMarkIcon): Integer;
+begin
+ {$IFDEF FUI_TEXT_ICONS}
+ case ic of
+ TMarkIcon.Checkbox: result := textWidth('[x]');
+ TMarkIcon.Radiobox: result := textWidth('(*)');
+ else result := textWidth('[x]');
+ end;
+ {$ELSE}
+ result := 11;
+ {$ENDIF}
+end;
+
+function TGxContext.iconMarkHeight (ic: TMarkIcon): Integer;
+begin
+ {$IFDEF FUI_TEXT_ICONS}
+ case ic of
+ TMarkIcon.Checkbox: result := textHeight('[x]');
+ TMarkIcon.Radiobox: result := textHeight('(*)');
+ else result := textHeight('[x]');
+ end;
+ {$ELSE}
+ result := 8;
+ {$ENDIF}
+end;
procedure TGxContext.drawIconMark (ic: TMarkIcon; x, y: Integer; marked: Boolean);
var
+ {$IFDEF FUI_TEXT_ICONS}
+ xstr: AnsiString;
+ {$ELSE}
f: Integer;
+ {$ENDIF}
begin
if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
+ {$IFDEF FUI_TEXT_ICONS}
+ case ic of
+ TMarkIcon.Checkbox: xstr := '[x]';
+ TMarkIcon.Radiobox: xstr := '(*)';
+ else exit;
+ end;
+ if (marked) then
+ begin
+ drawText(x, y, xstr);
+ end
+ else
+ begin
+ drawChar(x, y, xstr[1]);
+ drawChar(x+textWidth(xstr)-charWidth(xstr[3]), y, xstr[3]);
+ end;
+ {$ELSE}
if (ic = TMarkIcon.Checkbox) then
begin
vline(x, y, 7);
hline(x+4, y+5, 3);
end;
end;
+ {$ENDIF}
end;
-function TGxContext.iconWinWidth (ic: TWinIcon): Integer; begin result := 9; end;
-function TGxContext.iconWinHeight (ic: TWinIcon): Integer; begin result := 8; end;
+function TGxContext.iconWinWidth (ic: TWinIcon): Integer;
+begin
+ {$IFDEF FUI_TEXT_ICONS}
+ case ic of
+ TWinIcon.Close: result := nmax(textWidth('[x]'), textWidth('[#]'));
+ else result := nmax(textWidth('[x]'), textWidth('[#]'));
+ end;
+ {$ELSE}
+ result := 9;
+ {$ENDIF}
+end;
+
+function TGxContext.iconWinHeight (ic: TWinIcon): Integer;
+begin
+ {$IFDEF FUI_TEXT_ICONS}
+ case ic of
+ TWinIcon.Close: result := nmax(textHeight('[x]'), textHeight('[#]'));
+ else result := nmax(textHeight('[x]'), textHeight('[#]'));
+ end;
+ {$ELSE}
+ result := 8;
+ {$ENDIF}
+end;
procedure TGxContext.drawIconWin (ic: TWinIcon; x, y: Integer; pressed: Boolean);
var
+ {$IFDEF FUI_TEXT_ICONS}
+ xstr: AnsiString;
+ wdt: Integer;
+ {$ELSE}
f: Integer;
+ {$ENDIF}
begin
if (not mActive) or (mClipRect.w < 1) or (mClipRect.h < 1) or (mColor.a = 0) then exit;
+ {$IFDEF FUI_TEXT_ICONS}
+ case ic of
+ TWinIcon.Close: if (pressed) then xstr := '[#]' else xstr := '[x]';
+ else exit;
+ end;
+ wdt := nmax(textWidth('[x]'), textWidth('[#]'));
+ drawChar(x, y, xstr[1]);
+ drawChar(x+wdt-charWidth(xstr[3]), y, xstr[3]);
+ drawChar(x+((wdt-charWidth(xstr[2])) div 2), y, xstr[2]);
+ {$ELSE}
if pressed then rect(x, y, 9, 8);
for f := 1 to 5 do
begin
vline(x+1+f, y+f, 1);
vline(x+1+6-f, y+f, 1);
end;
+ {$ENDIF}
end;
+procedure TGxContext.glSetScale (ascale: Single);
+begin
+ if (ascale < 0.01) then ascale := 0.01;
+ glLoadIdentity();
+ glScalef(ascale, ascale, 1.0);
+ mScale := ascale;
+ mScaled := (ascale <> 1.0);
+end;
+
+procedure TGxContext.glSetTrans (ax, ay: Single);
+begin
+ glLoadIdentity();
+ glScalef(mScale, mScale, 1.0);
+ glTranslatef(ax, ay, 0);
+end;
+
+
+procedure TGxContext.glSetScaleTrans (ascale, ax, ay: Single);
+begin
+ glSetScale(ascale);
+ glTranslatef(ax, ay, 0);
+end;
+
+
+// vertical scroll bar
+procedure TGxContext.drawVSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
+var
+ filled: Integer;
+begin
+ if (wdt < 1) or (hgt < 1) then exit;
+ filled := sbarFilled(hgt, cur, min, max);
+ color := clrfull;
+ fillRect(x, y, wdt, filled);
+ color := clrempty;
+ fillRect(x, y+filled, wdt, hgt-filled);
+end;
+
+
+// horizontal scrollbar
+procedure TGxContext.drawHSBar (x, y, wdt, hgt: Integer; cur, min, max: Integer; constref clrfull, clrempty: TGxRGBA);
+var
+ filled: Integer;
+begin
+ if (wdt < 1) or (hgt < 1) then exit;
+ filled := sbarFilled(wdt, cur, min, max);
+ color := clrfull;
+ fillRect(x, y, filled, hgt);
+ color := clrempty;
+ fillRect(x+filled, y, wdt-filled, hgt);
+end;
+
+
+class function TGxContext.sbarFilled (wh: Integer; cur, min, max: Integer): Integer;
+begin
+ if (wh < 1) then result := 0
+ else if (min > max) then result := 0
+ else if (min = max) then result := wh
+ else
+ begin
+ if (cur < min) then cur := min else if (cur > max) then cur := max;
+ result := wh*(cur-min) div (max-min);
+ end;
+end;
+
+
+class function TGxContext.sbarPos (cxy: Integer; xy, wh: Integer; min, max: Integer): Integer;
+begin
+ if (wh < 1) then begin result := 0; exit; end;
+ if (min > max) then begin result := 0; exit; end;
+ if (min = max) then begin result := max; exit; end;
+ if (cxy < xy) then begin result := min; exit; end;
+ if (cxy >= xy+wh) then begin result := max; exit; end;
+ result := min+((max-min)*(cxy-xy) div wh);
+ assert((result >= min) and (result <= max));
+end;
+
+
+
+
// ////////////////////////////////////////////////////////////////////////// //
(*
procedure oglRestoreMode (doClear: Boolean);
*)
-//procedure onWinFocus (); begin end;
-//procedure onWinBlur (); begin fuiResetKMState(true); end;
+//procedure onWinFocus (); begin uiFocus(); end;
+//procedure onWinBlur (); begin fuiResetKMState(true); uiBlur(); end;
//procedure onPreRender (); begin oglRestoreMode(gGfxDoClear); end;
procedure onPostRender (); begin oglDrawCursor(); end;
// ////////////////////////////////////////////////////////////////////////// //
initialization
savedGLState := TSavedGLState.Create(false);
- createFonts();
+ //createFonts();
//winFocusCB := onWinFocus;
//winBlurCB := onWinBlur;
//prerenderFrameCB := onPreRender;