// スキン情報とスキンデータローダー // あぁクソコードすぎて話になんねえ…('A`) private { import win32.windows; import uxtheme; import inifile; import shgetfileinfo; import std.string; import std.utf; import std.path; } // 文字列を数値に変換するテンプレート private import std.conv; template StringToIntegral2(T) { T StringToIntegral2(char[] s, uint base) in { assert( base <= 36 ); assert( s.length > 0 ); // assert( is_signed!(T) || s[0]!='-' ); } body { int sign = (s[0]=='-' ? -1 : +1); if( s[0]=='-' || s[0]=='+' ) s = s[1 .. s.length]; T result = 0; foreach(char c ; s) { T v = T.max; if( '0'<=c && c<='9' ) v = c-'0'; else if( 'A'<=c && c<='Z' ) v = c-'A'+10; else if( 'a'<=c && c<='z' ) v = c-'a'+10; if( v >= base ) throw new ConvError(s); v = result*base + sign*v; if( sign>0 && vresult ) throw new ConvOverflowError(s); result = v; } return result; } } alias StringToIntegral2!(ubyte) str2ub; // スキンローダー SkinParts LoadSkinParts(char[] filename) { SkinParts result; IniFile ini = new IniFile(filename); char[][] sections = ini.GetSectionNames(); foreach (char[] section; sections.sort) { Skin part; section = tolower(section); // MessageBox(null, toUTF16z(section), "Section", MB_OK); char[][] sectioninfo = split(section, "."); // MessageBox(null, toUTF16z(sectioninfo[length-1]), toUTF16z(section), MB_OK); switch (sectioninfo[length-1]) { case "text": part = new SkinText; char[][] margin = split(ini.GetString(section, "Margin", "0,0,0,0"), ","); part.Margin(atoi(margin[0]), atoi(margin[1]), atoi(margin[2]), atoi(margin[3])); part.Color = ini.GetString(section, "Color", "000000"); part.FontSize = ini.GetInteger(section, "FontSize", 10); part.FontFamily = ini.GetString(section, "FontFamily", "Tahoma"); part.Align = ini.GetString(section, "Align", ""); part.VerticalAlign = ini.GetString(section, "VerticalAlign", ""); part.Weight = ini.GetString(section, "Weight", ""); part.Italic = ini.GetInteger(section, "Italic", 0) ? true : false; part.Underline = ini.GetInteger(section, "Underline", 0) ? true : false; part.Strikeout = ini.GetInteger(section, "StrikeOut", 0) ? true : false; break; case "icon": part = new SkinIcon; char[][] pos = split(ini.GetString(section, "Position", "0,0"), ","); part.Position(atoi(pos[0]), atoi(pos[1])); part.IconSize = ini.GetString(section, "Size", "Large"); break; default: if (IsThemeActive() && ini.GetInteger(section, "ThemeAPI", 0)) { // VisualStyle適用 part = new SkinVS(ini.GetString(section, "ThemeClass", "Window"), ini.GetInteger(section, "ThemePart", 1), ini.GetInteger(section, "ThemeState", 1)); } else { // 通常 part = new SkinNormal; if (ini.GetString(section, "Image", "").length > 0) { // MessageBox(null, "image", "", MB_OK); (cast(SkinNormal)part).Image = std.path.getDirName(filename) ~ "\\" ~ ini.GetString(section, "Image", ""); } else { // MessageBox(null, "color", "", MB_OK); (cast(SkinNormal)part).Color = ini.GetString(section, "Color", "FFFFFF"); } } // 共通項目 part.Width = ini.GetInteger(section, "Width", -1); part.Height = ini.GetInteger(section, "Height", -1); } // 親子情報の設定 if (sectioninfo.length > 1) { foreach (char[] parent_name; result.keys) { // 親キー生成 char[] parent_key = sectioninfo[0]; for (int i = 1; i < sectioninfo.length - 1; i++) { parent_key ~= "." ~ sectioninfo[i]; } if (parent_key == parent_name) { // MessageBox(null, toUTF16z(sectioninfo[length-1]), toUTF16z(parent_key), MB_OK); part.Parent = result[parent_name]; result[parent_name].AddChild(sectioninfo[length-1], part); break; } } } // result[sectioninfo[length-1]] = part; result[section] = part; } return result; } // 型定義 alias Skin[char[]] SkinParts; // スキンインターフェース interface Skin { // Background Properties int Width(); int Height(); void Width(int cx); void Height(int cy); void DrawBackground(HWND hWnd, HDC hdc, RECT rect); // Properties for Text void Margin(int top, int left, int right, int bottom); void Color(char[] colorref); void FontSize(int size); void FontFamily(char[] family_name); void Align(char[] flag); void VerticalAlign(char[] flag); void Weight(char[] flag); void Italic(bool value); void Underline(bool value); void Strikeout(bool value); void DrawText(HDC hdc, char[] text, RECT rect); // Properties for Icon void Position(int x, int y); void IconSize(char[] flag); void DrawIcon(HDC hdc, char[] filename); void DrawIcon(HDC hdc, char[] filename, uint index); // Common Control void Parent(Skin skin); Skin Parent(); void AddChild(char[] name, Skin child_part); Skin GetChild(char[] name); } // スキン共通定義 class SkinBase : Skin { protected: int width, height; Skin parent; SkinParts children; public: // Background Properties int Width(){} int Height(){} void Width(int cx) { width = cx; } void Height(int cy){ height = cy; } void DrawBackground(HWND hWnd, HDC hdc, RECT rect){} // Properties for Text void Margin(int top, int left, int right, int bottom){} void Color(char[] colorref){} void FontSize(int size){} void FontFamily(char[] family_name){} void Align(char[] flag){} void VerticalAlign(char[] flag){} void Weight(char[] flag){} void Italic(bool value){} void Underline(bool value){} void Strikeout(bool value){} void DrawText(HDC hdc, char[] text, RECT rect){} // Properties for Icon void Position(int x, int y){} void IconSize(char[] flag){} void DrawIcon(HDC hdc, char[] filename){} void DrawIcon(HDC hdc, char[] filename, uint index){} // Common Controll void Parent(Skin skin) { parent = skin; } Skin Parent() { return parent; } void AddChild(char[] name, Skin child_part) { assert(child_part); children[name] = child_part; } Skin GetChild(char[] name) { if (name in children) { return children[name]; } else { assert(0); } } } // VisualStyle適用テーマ class SkinVS : SkinBase { private: HTHEME hTheme; char[] classname; int part, state; public: this() {} this(char[] classname, int part_id, int state_id) { if (IsThemeActive()) { hTheme = OpenThemeData(null, toUTF16z(classname)); } assert(hTheme); part = part_id; state = state_id; } void DrawBackground(HWND hWnd, HDC hdc, RECT rect) { // if (IsThemeBackgroundPartiallyTransparent(hTheme, part, state)) { // DrawThemeParentBackground(hWnd, hdc, NULL); // } DrawThemeBackground(hTheme, hdc, part, state, &rect, NULL); } // VSを使ったテキスト描画(現段階で黒抜けの解決法なし…) // void DrawText(HDC hdc, char[] text, RECT rect) { // RECT content_rect; // GetThemeBackgroundContentRect(hTheme, hdc, part, state, &rect, &content_rect); // LOGFONT font; // if (S_OK != GetThemeFont(hTheme, null, part, state, 0, &font)) { // GetThemeSysFont(hTheme, TMT_CAPTIONFONT, &font); // MessageBox(null, "can't get font", "", MB_OK); // } // GetThemeSysFont(hTheme, TMT_CAPTIONFONT, &font); // SetBkMode(hdc, TRANSPARENT); // SetTextColor(hdc, GetThemeSysColor(hTheme, TMT_CAPTIONTEXT)); // SetTextColor(hdc, RGB(255,255,255)); // HFONT hFont = CreateFontIndirect(&font); // HFONT hOldFont = SelectObject(hdc, hFont); // DrawThemeText(hTheme, hdc, part, state, // toUTF16z(text), -1, // DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, // &content_rect); // win32.windows.DrawText(hdc, toUTF16z(text), -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_WORDBREAK); // SelectObject(hdc, hOldFont); // DeleteObject(hFont); // } int Width() { if (width == -1) { SIZE size; GetThemePartSize(hTheme, null, part, state, null, THEMESIZE.TS_TRUE, &size); return size.cx; } else { return width; } } int Height() { if (height == -1) { SIZE size; GetThemePartSize(hTheme, null, part, state, null, THEMESIZE.TS_TRUE, &size); return size.cy; } else { return height; } } } // 通常スキン class SkinNormal : SkinBase { private: COLORREF color; HBITMAP hImage; public: ~this() { if (hImage) { DeleteObject(hImage); } } int Width() { if (hImage !is null) { BITMAP bmp; GetObject(hImage, BITMAP.sizeof, &bmp); return bmp.bmWidth; } else { return width; } } int Height() { if (hImage !is null) { BITMAP bmp; GetObject(hImage, BITMAP.sizeof, &bmp); return bmp.bmHeight; } else { return height; } } void Color(char[] colorref) { color = RGB( str2ub(colorref[0..2], 16), str2ub(colorref[2..4], 16), str2ub(colorref[4..6], 16) ); } void Image(char[] string) { hImage = cast(HBITMAP) LoadImage(null, toUTF16z(string), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE); } void DrawBackground(HWND hWnd, HDC hdc, RECT rect) { if (Width == 0 || Height == 0) return; if (hImage !is null) { HDC hBitmapDC = CreateCompatibleDC(hdc); SelectObject(hBitmapDC, hImage); StretchBlt(hdc, rect.left, rect.top, rect.right, rect.bottom, hBitmapDC, 0, 0, Width, Height, SRCCOPY); DeleteDC(hBitmapDC); } else { HBRUSH hBrush = CreateSolidBrush(color); FillRect(hdc, &rect, hBrush); DeleteObject(hBrush); } } } // テキスト用 class SkinText : SkinBase { private: int[char[]] margin; COLORREF color; int font_size; char[] font_family; int weight; DWORD italic, underline, strikeout; DWORD format; public: void Margin(int top, int left, int right, int bottom) { margin["top"] = top; margin["left"] = left; margin["right"] = right; margin["bottom"] = bottom; } void Color(char[] colorref) { color = RGB( str2ub(colorref[0..2], 16), str2ub(colorref[2..4], 16), str2ub(colorref[4..6], 16) ); } void FontSize(int size) { font_size = size; } void FontFamily(char[] family_name) { font_family = family_name; } void Align(char[] flag) { switch (tolower(flag)) { case "left": format |= DT_LEFT; break; case "right": format |= DT_RIGHT; break; case "center": default: format |= DT_CENTER; } } void VerticalAlign(char[] flag) { switch (tolower(flag)) { case "center": format |= DT_VCENTER | DT_SINGLELINE; break; case "bottom": format |= DT_BOTTOM | DT_SINGLELINE; break; default: } } void Weight(char[] flag) { switch (tolower(flag)) { case "light": weight = FW_LIGHT; break; case "bold": weight = FW_BOLD; break; default: weight = FW_DONTCARE; } } void Italic(bool value) { italic = value ? TRUE : FALSE; } void Underline(bool value) { underline = value ? TRUE : FALSE; } void Strikeout(bool value) { strikeout = value ? TRUE : FALSE; } void DrawText(HDC hdc, char[] text, RECT rect) { rect.top += margin["top"]; rect.left += margin["left"]; rect.right -= margin["right"]; rect.bottom -= margin["bottom"]; int font_height = -MulDiv(font_size, GetDeviceCaps(hdc, LOGPIXELSY), 72); SetTextColor(hdc, color); SetBkMode(hdc, TRANSPARENT); HFONT hFont = CreateFont(font_height, 0, 0, 0, weight, italic, underline, strikeout, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, toUTF16z(font_family)); HFONT hOldFont = cast(HFONT) SelectObject(hdc, hFont); win32.windows.DrawText(hdc, toUTF16z(text), -1, &rect, format | DT_WORDBREAK | DT_EXPANDTABS); SelectObject(hdc, hOldFont); DeleteObject(hFont); } } // アイコン用 class SkinIcon : SkinBase { private: int pos_x, pos_y; int[char[]] position; bool small_size; public: void Position(int x, int y) { position["x"] = x; position["y"] = y; } void IconSize(char[] flag) { switch (tolower(flag)) { case "small": small_size = true; break; case "large": default: small_size = false; } } void DrawIcon(HDC hdc, char[] filename) { HICON hIcon; hIcon = GetFileIconHandle(filename, small_size); DrawIconEx(hdc, position["x"], position["y"], hIcon, small_size ? 16 : 32, small_size ? 16 : 32, 0, NULL, DI_NORMAL); DestroyIcon(hIcon); } void DrawIcon(HDC hdc, char[] filename, uint index) { HICON hLargeIcon, hSmallIcon; ExtractIconEx(toUTF16z(filename), index, &hLargeIcon, &hSmallIcon, 1); DrawIconEx(hdc, position["x"], position["y"], small_size ? hSmallIcon : hLargeIcon, small_size ? 16 : 32, small_size ? 16 : 32, 0, NULL, DI_NORMAL); DestroyIcon(hLargeIcon); DestroyIcon(hSmallIcon); } }