// Objektorientierte GDI-Kapselung
#pragma once
#include <windows.h>
#include <windowsx.h>
#include <limits>
#include <commctrl.h> // GetEffectiveClientRect
#ifndef Float
# define Float float // Wertekoordinaten: hier 4-Byte-Gleitkomma
#endif
typedef LONG Int; // Anzeigekoordinaten, muss zum Elementtyp von Rect (= RECT) passen
#if _MSC_VER >= 1400
# define FINF (std::numeric_limits<Float>::infinity())
#else
const unsigned FNAN=0xFFFFFFFF; // Bei double anpassen! unsigned __int64 0xFFFFFFFFFFFFFFFF
const unsigned FINF=0x7F800000; // unsigned __int64 0x7FF0000000000000
#define FNAN (*(Float*)&FNAN) // #defines rekursieren nicht
#define FINF (*(Float*)&FINF)
#endif
const Int INAN=Int(0x80000000);
const Int IINF= 0x7FFFFFFF;
/* Fast schon langweilige Objektifizierungen = Kapselklassen von GDI-Krimskrams
Kann so leichter auf GDIplus umgestellt werden
*/
struct Rect:public RECT{ // Bei GdiPlus: RectF? Nee! RectF definiert sich gegenüber RECT durch Breite und Höhe!
operator SIZE() const {SIZE sz={width(),height()}; return sz;}
Int width() const {return right-left;}
Int height() const {return bottom-top;}
Int center() const {return (left+right)>>1;}
Int middle() const {return (top+bottom)>>1;}
Int byIndex(int i) const {
if ((unsigned)i<4) return (&left)[i];
switch (i) {
case 4: return width();
case 5: return height();
case 6: return -width();
case 7: return -height();
case 8: return center();
case 9: return middle();
default: return INAN;
}
}
Int operator[](int i) const {return byIndex(i);}
Int&at(int i) {
if ((unsigned)i<4) return (&left)[i];
return *(Int*)0;
}
Int addTo(size_t i,Int v) {
if (i>=4) return 0;
return (&left)[i]+=v;
}
bool intersect(const Rect*r2) const{
if (!r2) return true;
Rect rd;
return !!IntersectRect(&rd,this,r2);
}
void inflate(Int dx,Int dy) {InflateRect(this,dx,dy);} // aufblasen
void deflate(Int dx,Int dy) {inflate(-dx,-dy);} // verkleinern
void offset(Int dx,Int dy) {OffsetRect(this,dx,dy);} // versetzen
Rect() {}
Rect(HWND w) {GetWindowRect(w,this);}
Rect(HWND w, bool x) {GetClientRect(w,this);}
Rect(HWND w, const int*info) {GetEffectiveClientRect(w,this,const_cast<int*>(info));}
bool inside(const POINT&pt) const {return !!PtInRect(this,pt);}
};
struct Margin:public RECT{
Margin() {init();}
Margin(Int l,Int t,Int r,Int b) {init(l,t,r,b);}
void init() {init(0,0,0,0);}
void init(const Margin&m) {init(m.left,m.top,m.right,m.bottom);}
void init(Int l,Int t,Int r,Int b) {left=l;top=t;right=r;bottom=b;}
void expand(const Margin&m) {expand(m.left,m.top,m.right,m.bottom);}
void expand(Int l,Int t,Int r,Int b) {
if (left<l) left=l;
if (top<t) top=t;
if (right<r) right=r;
if (bottom<b) bottom=b;}
Int getW() const {return left+right;} // Gesamtrand horizontal
Int getH() const {return top+bottom;} // Gesamtrand vertikal
Int operator[](size_t i) const {switch (i) {
case 0:case 1:case 2:case 3:return (&left)[i];
case 4: return getW();
case 5: return getH();
default: return INAN;}}
Int addTo(size_t i,Int v) {
if (i>=4) return 0;
return (&left)[i]+=v;
}
};
#if _MSC_VER >= 1400
# define NODEFAULT =delete // bei neuerem C++
#else
# define NODEFAULT
#endif
struct Color{
COLORREF c;
Color(COLORREF cr=0):c(cr) {} // TODO: Transparent initialisieren!! Hier: Schwarz
Color(BYTE r, BYTE g, BYTE b, BYTE t=0):c(RGB(r,g,b)) {}
Color operator=(COLORREF cr) {return c=cr;}
operator COLORREF() const {return c;}
};
struct GdiObj{
HGDIOBJ h;
GdiObj(HGDIOBJ obj=0):h(obj) {}
GdiObj(GdiObj&obj):h(obj) {obj.h=0;}
GdiObj operator=(GdiObj&obj) {if (h) DeleteObject(h); h=obj; obj.h=0; return*this;}
GdiObj operator=(HGDIOBJ obj) {if (h) DeleteObject(h); return h=obj;}
~GdiObj() {if (h) DeleteObject(h);}
operator HGDIOBJ() const {return h;} // wenn HGDIOBJ gefragt wird
operator bool() const {return !!h;}
bool operator!() const {return !h;}
};
struct Pen:public GdiObj{
Pen(HPEN pen=0):GdiObj(pen) {} // Achtung! Destruktor zerstört den Stift!
Pen(Pen&pen):GdiObj(pen) {pen.h=0;}
// Pen(const Pen&)NODEFAULT; // Dreierregel: Kopieren und Zuweisen verboten
// Pen&operator=(const Pen&)NODEFAULT;
static HPEN create(int width, Color color) {return CreatePen(PS_SOLID,width,color);}
static HPEN create(int style,int width,Color color) {return CreatePen(style,width,color);}
Pen(int width,Color color):GdiObj(create(width,color)) {}
Pen(int style,int width,Color color):GdiObj(create(style,width,color)) {}
void operator=(HPEN p) {if (h) DeletePen(h); h=p;}
operator HPEN() const {return (HPEN)h;} // wenn HPEN gefragt wird
};
struct Brush:public GdiObj{
Brush(HBRUSH br=0):GdiObj(br) {} // Achtung! Destruktor zerstört den Pinsel!
static HBRUSH create(Color color) {return CreateSolidBrush(color);}
static HBRUSH create(int hatch, Color color) {CreateHatchBrush(hatch,color);}
Brush(Color color):GdiObj(create(color)) {}
Brush(int hatch, Color color):GdiObj(create(hatch,color)) {}
void operator=(HBRUSH br) {if (h) DeleteBrush(h); h=br;}
operator HBRUSH() const {return (HBRUSH)h;} // wenn HBRUSH gefragt wird
};
struct Font:public GdiObj{
enum{ // Font-Flags
bold=4,
italic=8,
underline=16,
strikeout=32,
symbol=64,
};
struct Data{
TCHAR*name;
int size;
int flags;
int rotation;
HFONT operator()() const {
return CreateFont(size,0,rotation,rotation,
flags&bold?FW_BOLD:FW_NORMAL,
flags&italic?TRUE:FALSE,
flags&underline?TRUE:FALSE,
flags&strikeout?TRUE:FALSE,
flags&symbol?SYMBOL_CHARSET:ANSI_CHARSET,
OUT_TT_PRECIS,
CLIP_DEFAULT_PRECIS,
PROOF_QUALITY,// lf.lfQuality=CLEARTYPE_QUALITY;
DEFAULT_PITCH|FF_DONTCARE,
name);
}
Data&operator()(HFONT f) {
LOGFONT lf;
GetObject(f,sizeof lf,&lf);
rotation=lf.lfOrientation;
flags=0;
if (lf.lfWeight>FW_NORMAL) flags|=bold;
if (lf.lfItalic) flags|=italic;
if (lf.lfUnderline) flags|=underline;
if (lf.lfStrikeOut) flags|=strikeout;
if (lf.lfCharSet==SYMBOL_CHARSET) flags|=symbol;
size=lf.lfHeight;
lstrcpyn(name,lf.lfFaceName,LF_FACESIZE);
}
};
struct Data1:public Data{
TCHAR buf[LF_FACESIZE];
Data1&operator=(const Data&d) {memcpy(this,&d,sizeof d); lstrcpyn(buf,name,LF_FACESIZE);}
Data1&operator=(const Data1&d) {memcpy(this,&d,sizeof*this);}
HFONT operator()() {name=buf; return Data::operator()();}
Data1&operator()(HFONT f) {name=buf; return (Data1&)Data::operator()(f);}
};
Font(HFONT f=0):GdiObj(f) {} // Achtung! Destruktor zerstört die Schrift!
// Font(Font&f):h(f.h) {f.h=0;} // Raubkopie, geht das?
// Font(const Font&)NODEFAULT;
// Font&operator=(const Font&)NODEFAULT;
Font(HWND w):GdiObj(GetWindowFont(w)) {} // avoid destruction by setting Font::h=0 before scope leaving!
Font(HDC dc):GdiObj(GetCurrentObject(dc,OBJ_FONT)) {}
#ifdef _M_IX86
static HFONT _stdcall create(LPCTSTR name,int size,BYTE flags=0,int rotation=0) {
Data&d=*(Data*)&name; // Parameter direkt vom Stack nehmen
return d();
}
#else
static HFONT create(LPCTSTR name,int size,BYTE flags=0,int rotation=0) {
Data d={const_cast<TCHAR*>(name),size,flags,rotation}; // Parameter umstapeln
return d();
}
#endif
static HFONT create(const Data&d) {return d();}
Font(LPCTSTR name,int size,BYTE flags=0,int rotation=0):GdiObj(create(name,size,flags,rotation)) {}
Font(const Data&d):GdiObj(d()) {}
Font(Data1&d):GdiObj(d()) {}
Font(const LOGFONT&lf):GdiObj(CreateFontIndirect(&lf)) {}
void query(LOGFONT&lf) {GetObject(h,sizeof lf,&lf);}
void query(Data&d) {d(HFONT(h));}
void query(Data1&d) {d(HFONT(h));}
void operator=(HFONT f) {if (h) DeleteFont(h); h=(HGDIOBJ)f;}
operator HFONT() const {return (HFONT)h;} // wenn HFONT gefragt wird
};
// A small metric structure suitable for function return: 32 bits
// All four needed Y values for font processing; extlead only for multi-line text
struct Metric{
BYTE height,ascent,intlead,extlead;
Metric(const TEXTMETRIC&tm):
height(BYTE(tm.tmHeight)), // Height of "Äq"
ascent(BYTE(tm.tmAscent)), // Height of "Ä"
intlead(BYTE(tm.tmInternalLeading)), // Height of "Ä" - "A"
extlead(BYTE(tm.tmExternalLeading)) {} // multi-line gap (Durchschuss)
Metric(HDC dc) {
TEXTMETRIC tm;
GetTextMetrics(dc,&tm);
height=BYTE(tm.tmHeight);
ascent=BYTE(tm.tmAscent);
intlead=BYTE(tm.tmInternalLeading);
extlead=BYTE(tm.tmExternalLeading);
}
BYTE descent() const {return height-ascent;} // Unterlänge
};
Detected encoding: ANSI (CP1252) | 4
|
|