AviUtl2ã®èè²ããã®ããŒã¯ã¢ãŒããã©ã°ã€ã³ã®ä»æ§ææ¡ã¡ã¢
ðAviUtl2 ããŒã¯ã¢ãŒããã©ã°ã€ã³ãal2_jdã
ã¯ããã«
è²ã
åŒã£ãŠãã®ã§æè§ãªã®ã§å人çã¡ã¢ãå
¬éçšã«ç·šéããŠå
±æããŸãããå
容ã«ééããåéãããããããããŸãããèªå·±è²¬ä»»ã§ãé¡ãããŸãã
al2_jd-r6ã®æ
å ±ã§ãèŠã«ããã®ã¯ä»æ§ã§ã
æŠèŠ
AviUtl2ã®UIãããŒã¯ã¢ãŒãåããããã®å
¥åãã©ã°ã€ã³
Windowsã®æšæºæç»åŠçã«ä»å
¥ããUIèŠçŽ ã®é
è²ãã¹ã¿ã€ã«ãåçã«å€æŽããããšã§ãã¢ããªã±ãŒã·ã§ã³å
šäœã®å€èгãçµ±äžæã®ããããŒã¯ã¢ãŒãã«åãæ¿ããŠãã
ã³ã¢ã¢ãŒããã¯ãã£ïŒããã¯ãã¬ã³ãã©ãŒããã€ã³ã
æ¬ãã©ã°ã€ã³ã¯ã責åãæç¢ºã«åé¢ããã3å±€ã®ã¢ãŒããã¯ãã£ã§æ§æãããŠãã
3å±€æ§é ã®æŠèŠ
1. ããã¯å±€ (kuro/hook/)
Windows APIãžã®ä»å
¥ãæ
åœãæç»é¢é£ã®APIåŒã³åºããææ
2. ã¬ã³ãã©ãŒå±€ (kuro/gdi/, kuro/theme/)
ææããæç»åŠçããã³ã³ãããŒã«ã®çš®é¡ã«å¿ããŠé©åãªæç»ããžãã¯ã«æ¯ãåã
3. ãã€ã³ãå±€ (kuro/paint/)
å®éã®æç»ã«äœ¿ãããè²ããã©ã·ããã©ã³ããªã©ã®ãæç»çŽ æãã管çã»æäŸ
ã·ã¹ãã æ§æå³
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Windowsã¢ããªã±ãŒã·ã§ã³ (AviUtl2) ã ãã â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â â
â (æç»APIåŒã³åºã) â (ãŠã£ã³ããŠã¡ãã»ãŒãž)
â â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â ãããã¯å±€ã Detoursã«ããAPIãã㯠ãã ãã ã â
â - GDI API (FillRect, ExtTextOutW, etc.) â
â - Theme API (DrawThemeBackground, etc.) â
â - Window Message (WM_CREATE, WM_PAINT, etc.) â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
â (ããã¯ããæç»åŠçããã£ã¹ããã)
â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â ãã¬ã³ãã©ãŒå±€ã GDI / Theme ã¬ã³ãã©ãŒ â
â - GdiRenderer (ãµãã¯ã©ã¹åã§MSGãåŠç) ããããâ
â - ThemeRenderer (ããŒããã³ãã«ã§åŠçãåå²) ã â
â - ButtonRenderer, ListBoxRenderer, etc.(åã³ã³ãããŒã«å°çš)â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â
â (æç»ã«å¿
èŠãªè²ãã¹ã¿ã€ã«ãåãåãã)
â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â ããã€ã³ãå±€ã ãããªã¢ã« / ãã¬ãã / ã¹ã¿ã€ã©ã¹ â
â - Material: ã³ã³ãããŒã«ããšã®æç»çŽ æå®çŸ© â
â - Palette: ç¶æ
(éåžž/ãããŒç)ãšè²ã®ãããã³ã° â
â - Pigment: å
·äœçãªè²æ
å ± (èæ¯/忝/å¢ç) ã ãã â
â - Stylus: æç»å®è¡ãŠãŒãã£ãªã㣠â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ第1å±€ïŒæç»ããã¯ã·ã¹ãã (kuro/hook/)
UIæç»ãææ¡ããããã®å ¥ãå£ã2çš®é¡ã®æ¹æ³ã§æç»åŠçã«ä»å ¥
1. APIãã㯠(Detours)
Microsoft補ã®Detoursã©ã€ãã©ãªã䜿çšããæç»é¢é£ã®Windows APIãçŽæ¥ããã¯
.GDI APIãã㯠(gdi.hpp)
FillRect, ExtTextOutW, DrawEdgeãªã©ãããŒããé©çšãããªãã¬ã¬ã·ãŒãªUIã³ã³ããŒãã³ãã䜿çšããGDI颿°ãããã¯ãæšæºã³ã³ãããŒã«ã®åºæ¬çãªæç»ãã«ã¹ã¿ã æç»ã«çœ®ãæãã
.ããŒãAPIãã㯠(theme.hpp)
DrawThemeBackground, DrawThemeText, OpenThemeDataãªã©ã
Windowsã®èŠèŠã¹ã¿ã€ã«(ããŒã)ãæ±ãAPIãããã¯ãOpenThemeDataãããã¯ããããšã§ãã³ã³ãããŒã«ãããŒããã³ãã«ãååŸããéã«ããã®ãã³ãã«ãšã«ã¹ã¿ã ã¬ã³ãã©ãŒãçŽä»ããUIã®æç»ãææ¡
2. ãŠã£ã³ããŠãã㯠(call_wnd_proc_ret.hpp)
SetWindowsHookEx ãçšã㊠WH_CALLWNDPROCRET ããã¯ãèšå®
.ç®çïŒWM_CREATE ã¡ãã»ãŒãžã®åŠçå®äºæãææããæ°ããäœæãããå šãŠã®ãŠã£ã³ããŠã«GDIã¬ã³ãã©ãŒãã¢ã¿ãããããã«ãããåçã«çæããããã€ã¢ãã°ãã³ã³ãããŒã«ãæŒãããããŒã¯ã¢ãŒãã®å¯Ÿè±¡ã«ãã
第2å±€ïŒã¬ã³ãã©ãŒã·ã¹ãã (kuro/gdi/, kuro/theme/)
ããã¯å±€ããæž¡ãããæç»åŠçããå ·äœçãªããžãã¯ã«ç¹ãããäžæ žéšå
GDIã¬ã³ãã©ãŒ (gdi::Renderer)
ã¬ã¬ã·ãŒUIã®æç»ãæ åœãããéåžžã«å·§åŠãªã·ã¹ãã (ããã)
ãŠã£ã³ããŠã®ãµãã¯ã©ã¹å
WH_CALLWNDPROCRETããã¯ã«ãã£ãŠã¢ã¿ãããããåŸã察象ã®ãŠã£ã³ããŠãSetWindowSubclassã§ãµãã¯ã©ã¹åãããã®ãŠã£ã³ããŠã¡ãã»ãŒãžã subclass_proc ã§å šãŠåå
ã¡ãã»ãŒãžãã£ã¹ããã
subclass_proc ã¯ãWM_CTLCOLORxxxã NM_CUSTOMDRAW ãªã©ã®æç»é¢é£ã¡ãã»ãŒãžãæ€ç¥ãããšãon_ctl_color()ãªã©ã®ä»®æ³é¢æ°ãåŒã³åºããå ·äœçãªæç»åŠçãžç¹ã
thread_localã«ããåŒã³åºãå ç¹å®
GDIã®ããã¯é¢æ°(äŸ: FillRectã®ããã¯)ãåŒã°ããéãã©ã®ãŠã£ã³ããŠã®æç»åŠçãªã®ããç¹å®ããå¿ èŠããã
ãã®åé¡ã解決ããã®ã thread_local 倿° current_message_stateïŒ
subclass_proc ãã¡ãã»ãŒãžãåãåããã³ã«ããã®ã¹ã¬ããããŒã«ã«å€æ°ã«çŸåšã®ãŠã£ã³ããŠãã³ãã«ãã¡ãã»ãŒãžæ å ±ãä¿å
ãã®åŸãFillRectãªã©ã®GDIããã¯é¢æ°ãåŒã°ãããšããã®å€æ°ããåŒã³åºãå ã®ãŠã£ã³ããŠãç¹å®
ãã®ãŠã£ã³ããŠã«çŽä»ããã¬ã³ãã©ãŒã®ã¡ãœãã (on_fill_rect()) ãåŒã³åºã
ããŒãã¬ã³ãã©ãŒ (theme::Renderer)
ã¢ãã³UIã®æç»ãæ åœ
åçãªã¬ã³ãã©ãŒå·®ãæ¿ã
OpenThemeDataããã¯ã®æç¹ã§ããŠã£ã³ããŠã®ã¯ã©ã¹å(Button, Editãªã©)ãåºã«å¯Ÿå¿ããã«ã¹ã¿ã ã¬ã³ãã©ãŒ
(ButtonRenderer, EditboxRendererãªã©)ãããŒããã³ãã«ã«çŽä»ãããã
ä»®æ³é¢æ°ã«ããæç»
ãã®åŸãDrawThemeBackgroundãªã©ãåŒã°ãããšãããŒããã³ãã«ã«çŽä»ããã¬ã³ãã©ãŒã®ä»®æ³é¢æ° (on_draw_theme_background()) ãåŒã³åºãããã«ã¹ã¿ã æç»ãå®è¡ããã
第3å±€ïŒãã€ã³ãã·ã¹ãã (kuro/paint/)
ãäœãããã©ã®ããã«ãæç»ããããå®çŸ©ããããã¶ã€ã³ã·ã¹ãã ã®åœ¹å²
ãããªã¢ã« (Material)
ãã¿ã³ããªã¹ãããã¯ã¹ãšãã£ãUIã³ã³ãããŒã«ã®çš®é¡ããšã«å®çŸ©ããããæç»çŽ æãã®éåäœ
ãã¬ãã (Palette)
ãããªã¢ã«å ã«ä¿æãããã³ã³ãããŒã«ã®éšåID (part_id) ãšç¶æ ID (state_id) ã®ãã¢ãããŒãšããŠãå ·äœçãªæç»æ å ± (Pigment) ããããã³ã°
äŸïŒ
(BP_PUSHBUTTON, PBS_NORMAL) â éåžžç¶æ ã®ãã¿ã³çšã®Pigment
(BP_PUSHBUTTON, PBS_HOT) â ãããŒç¶æ ã®ãã¿ã³çšã®Pigment
ãã°ã¡ã³ã (Pigment)
æç»ã«å¿ èŠãªè²ã®çµã¿åãã(èæ¯è²ã忝è²ãå¢çè²ãªã©)ãä¿æããæ§é äœãJSONãã¡ã€ã«ããèªã¿èŸŒãŸããããŒãèšå®ãããã«æ ŒçŽããã
ã¹ã¿ã€ã©ã¹ (Stylus)
Pigmentæ å ±ãåãåããç©åœ¢æç»ãããã¹ãæç»ãšãã£ãå®éã®GDIæäœãå®è¡ãããŠãŒãã£ãªãã£ã¯ã©ã¹
ããŒã¯ã¢ãŒãå®è£ ã®è©³çްïŒè²ã®æ±ºå®ããæç»ãŸã§
ããŒã¯ã¢ãŒãã®å®è£ ã¯ããã€ã³ãå±€ãšã¬ã³ãã©ãŒå±€ã®é£æºã«ãã£ãŠå®çŸ
1. è²ã®å®çŸ© (å€éšãã¡ã€ã«é£æº)
ããŒã¯ã¢ãŒãã®é è²ã¯ãaviutl2ã®èšå®ãã¡ã€ã«style.confããåçã«èªã¿èŸŒã¿ãåã³ã³ãããŒã«ã®ãããªã¢ã«å®çŸ©ãã¡ã€ã«å (kuro/paint/material/*.hpp) ã§åç §ããŠãã
.è²å®çŸ©ã®éå±€æ§é
aviutl2/
âââ data/style.conf # ã¡ã€ã³ã®è²èšå®ãã¡ã€ã«(aviutl2æšæº)
âââ al2/config/al2_jd.json # ãã©ã°ã€ã³åºæã®èšå®(è§äžžãå¢çå¹
ãªã©)
âââ al2/assets/al2_jd.json # ããªã»ããæ
å ±.å®éã®è²ååŸåŠç
// kuro/paint/material/button.hpp(å®éã®å®è£
)
struct ButtonMaterial : Material {
virtual void on_init_material() override {
// ãã¿ã³ã®éåžžç¶æ
(PBS_NORMAL)
auto push_button_normal = Pigment {
{ style.get_COLORREF(Style::Color::ButtonBody), }, // â style.confããååŸ
{ style.get_COLORREF(Style::Color::Border), 1, }, // â style.confããååŸ
{ style.get_COLORREF(Style::Color::Text), }, // â style.confããååŸ
};
// ãããŒç¶æ
(PBS_HOT)
auto push_button_hot = Pigment {
{ style.get_COLORREF(Style::Color::ButtonBodyHover), }, // â style.confããååŸ
{ style.get_COLORREF(Style::Color::Border), 1, }, // â style.confããååŸ
{ style.get_COLORREF(Style::Color::Text), }, // â style.confããååŸ
};
// ãã¬ããã«ç»é²
palette.set(BP_PUSHBUTTON, PBS_NORMAL, push_button_normal);
palette.set(BP_PUSHBUTTON, PBS_HOT, push_button_hot);
// ...ãã®ä»ã®ç¶æ
ãåæ§ã«èšå®...
}
};è²ã®åªå é äœãšåçæŽæ°
style.conf(aviutl2ã®èšå®)ãæåªå ã§èªã¿èŸŒãŸãã
ãã©ã°ã€ã³ã®èšå®(è§äžžãå¢çå¹ ãªã©)ãé©çšããã
èµ·åæã« style.conf ãèªã¿èŸŒã¿ïŒèªååèªã¿èŸŒã¿ã¯æªå®è£ ïŒ
ãã®åæååŠçã¯ããã©ã°ã€ã³èµ·åæã« paint::manager.init() ããäžåºŠã ãåŒã³åºãããåãããªã¢ã«ã®ãã¬ããã«è²ãèšå®ããã
2. æç»ããã»ã¹
ãŠãŒã¶ãŒãUIãæäœããåæç»ãå¿ èŠã«ãªããšä»¥äžã®ããã»ã¹ãå®è¡ããã
.æç»ããªã¬ãŒ
OSãWM_PAINT ã¡ãã»ãŒãžãéä¿¡ããããã¢ããªã±ãŒã·ã§ã³ã DrawThemeBackground ãªã©ã®APIãåŒã³åºã
.ããã¯å±€ãææ
ãã©ã°ã€ã³ã®ããã¯å±€ããã®APIåŒã³åºããã¡ãã»ãŒãžãææ
ã¬ã³ãã©ãŒãžãã£ã¹ããã
ããã¯å±€ã¯ããŠã£ã³ããŠãã³ãã«ãããŒããã³ãã«ãåºã«ãé©åãªã¬ã³ãã©ãŒ(äŸ: ButtonRenderer)ãç¹å®ãããã®ã¡ãœãã
(äŸ: on_draw_theme_background)ãåŒã³åºãããã®æãåŒæ°ãšããŠHDC(ããã€ã¹ã³ã³ããã¹ã)ãæç»é åã瀺ãRECTããããŠã³ã³ãããŒã«ã®ç¶æ
ã瀺ãpart_idãšstate_idãæž¡ããã
GDIæäœå®è¡
paint::stylusã¯ãPigmentã«å«ãŸããè²æ å ±ã䜿ã£ãŠä»¥äžã®åŠçãå®è¡ïŒ
å¢çç·ããã®å Žå: PenAttribute(ãã³)ãšBrushAttribute(ãã©ã·)ãèšå®ããRectangleã§æç»
å¢çç·ãªãã®å Žå: CreateSolidBrushã§èæ¯è²ã®ãã©ã·ãäœæããFillRectã§å¡ãã€ã¶ã
ããã¹ãæç»: TextAttributeã§èæ¯è²ã»ããã¹ãè²ãèšå®ããExtTextOutWãDrawTextWã§æç»
ã¹ã¿ã€ã©ã¹ã®å ·äœçãªå®è£ äŸ
// stylus.hpp - ç©åœ¢æç»ã®å®éã®å®è£
BOOL draw_rect(HDC dc, LPCRECT rc, const Pigment* pigment) {
if (pigment->border.is_valid()) {
PenAttribute pen_attribute(dc, pigment); // å¢çç·çšãã³èšå®
BrushAttribute brush_attribute(dc, pigment); // èæ¯çšãã©ã·èšå®
return hive.orig.Rectangle(dc, rc->left, rc->top, rc->right, rc->bottom);
} else {
// å¢çç·ãªãã®å Žåã¯å¡ãã€ã¶ãã®ã¿
my::gdi::unique_ptr<HBRUSH> brush(::CreateSolidBrush(pigment->background.color));
return hive.orig.FillRect(dc, rc, brush.get());
}
}ãã®ããã«ããç¶æ ã«å¿ããè²ããããªã¢ã«ããååŸããã¹ã¿ã€ã©ã¹ã§æç»ããããšããäžé£ã®æµãããã¬ã³ãã©ãŒãä»ããŠå®è¡ãããããšã§ãUIå šäœãçµ±äžæã®ããããŒã¯ã¢ãŒãã§æç»ãããä»çµã¿ã«ãªã£ãŠãã
å®è£ ãã€ã©ã€ã
ã¹ã¬ããã»ãŒãèšèš
UIæäœã¯åäžã®ã¹ã¬ããã§è¡ãããããšãåæãšãã€ã€ãthread_local倿°ã掻çšããããšã§ãGDIããã¯ãšãŠã£ã³ããŠã¡ãã»ãŒãžåŠçãšããç°ãªãã³ã³ããã¹ãã飿ºãããŠãã
åçãªã¬ã³ãã©ãŒç®¡ç
std::unordered_map<HWND, std::shared_ptr<Renderer>> ã䜿çšããŠããŠã£ã³ããŠãã³ãã«ãšGDIã¬ã³ãã©ãŒã®ã€ã³ã¹ã¿ã³ã¹ãåçã«ç®¡çããŠã£ã³ããŠã®çæã»ç Žæ£ã«åãããŠãã¬ã³ãã©ãŒãèªåçã«çæã»ç Žæ£ããã
ãã©ã³ããã¬ãã¥ãŒæ©èœ
ãªã¹ãããã¯ã¹ã«é ç®ã远å ãããé (LB_ADDSTRING)ããã®æååãã·ã¹ãã ã«ååšãããã©ã³ãåããåçã«ãã§ãã¯
ãã©ã³ãåã§ããã°ããªã¹ãããã¯ã¹ã¯ExtTextOutWããã¯ïŒãµãã¯ã©ã¹ã§å®ãã©ã³ãæç»ããªã¹ããã¥ãŒã¯NM_CUSTOMDRAWã§ãã©ã³ãå·®ãæ¿ãããšãã圢ã§ãªã¢ã«ã¿ã€ã ãã¬ãã¥ãŒãå®çŸããŠãã
èšå®ã·ã¹ãã
èšå®é ç®
è§äžžãå¢çå¹ ãåœ±ã®æ¿åºŠããã©ã³ãèšå®ãèµ·åãªãã·ã§ã³ãªã©ãå€å²ã«ãããã«ã¹ã¿ãã€ãºé ç®ãæäŸ
èšå®ãã¡ã€ã«
al2_jd.json(å®éã¯ã¢ãžã¥ãŒã«åã«ç±æ¥)ã«èšå®ãä¿åããèµ·åæã«èªã¿èŸŒãããšã§æ°žç¶åãå®çŸ
ãã¡ã€ã«æ§æ
al2_jd/
âââ main.cpp # ãšã³ããªãã€ã³ãããã©ã°ã€ã³æ
å ±
âââ app.hpp # ã¢ããªã±ãŒã·ã§ã³å
šäœç®¡ç
âââ hive.hpp # ã°ããŒãã«èšå®ã»ç¶æ
管ç (æ
å ±ã®äžæ¢)
âââ config_dialog.hpp # èšå®ãã€ã¢ãã°
âââ config_io.hpp # èšå®ãã¡ã€ã«I/O
âââ kuro/ # â
ããŒã¯ã¢ãŒãåã³ã¢æ©èœ
â âââ hook/ # ã第1å±€ãAPIããã¯ç®¡ç
â â âââ gdi.hpp
â â âââ theme.hpp
â â âââ call_wnd_proc_ret.hpp
â âââ gdi/ # ã第2å±€ãGDIããŒã¹æç»
â â âââ renderer.hpp
â âââ theme/ # ã第2å±€ãããŒãããŒã¹æç»
â â âââ renderer.hpp
â âââ paint/ # ã第3å±€ãè²ã»ã¹ã¿ã€ã«ç®¡ç
â âââ material.hpp
â âââ palette.hpp
â âââ stylus.hpp
âââ common/ # å
±éãŠãŒãã£ãªãã£ãŸãšã
al2_jdã¯ãWindowsã®æç»ã·ã¹ãã ã®APIããã¯ããŠã£ã³ããŠãµãã¯ã©ã¹åããããŠåé¢ããã¯ãªãŒã³ãªã¢ãŒããã¯ãã£ãçµã¿åãããããšã§ãå ç¢ãã€æ¡åŒµæ§ã®é«ãUIã«ã¹ã¿ãã€ãºãå®çŸããŠãã
ç¹ã«thread_local倿°ãé§äœ¿ããŠããã¯ãšã¡ãã»ãŒãžåŠçã®ã³ã³ããã¹ããç¹ãã§ãã®ã¯æ®éã«ããããšæããããã0ããäœãã£ãŠèšãããŠãç§ã«ã¯çµ¶å¯Ÿã«ã§ããŸãããããããã¢ã«ãã£ã¡ãããã©ã°ã€ã³ïŒãšåä¹ã£ãŠè¯ãããããªãããªâŠ
ð§ããŸãïŒãŠã£ã³ããŠäœçœ®ä¿åæ©èœã®è¿œå
app.hppã®å€æŽç®æ
// dll_init()颿°å
// aviutl2ãŠã£ã³ããŠãæåé¢ã«
::SetForegroundWindow(hive.theme_window);
// aviutl2ãŠã£ã³ããŠãæå€§å
if (hive.maximize_aviutl2)
::ShowWindow(hive.theme_window, SW_MAXIMIZE);
// dll_exit()颿°å
// èšå®ãä¿åïŒã¡ã€ã³ãŠã£ã³ããŠã®äœçœ®ãå«ãïŒ
write_config();config_io.hpp
// ããŒãããã³ã³ãã£ã°ãèªã¿èŸŒã¿
virtual BOOL read_node(n_json& root)
{
MY_TRACE_FUNC("");
read_fonts(root);
read_new_project(root);
read_kuro(root);
read_window_pos(root, "config_dialog", config_dialog);
// ã¡ã€ã³ãŠã£ã³ããŠã®äœçœ®ã埩å
if (hive.theme_window)
{
read_window_pos(root, "main_window", hive.theme_window);
}
return TRUE;
}
// ããŒãã«ã³ã³ãã£ã°ãæžã蟌ã¿
virtual BOOL write_node(n_json& root)
{
MY_TRACE_FUNC("");
write_fonts(root);
write_new_project(root);
write_kuro(root);
write_window_pos(root, "config_dialog", config_dialog);
// ã¡ã€ã³ãŠã£ã³ããŠã®äœçœ®ãä¿å
if (hive.theme_window)
{
write_window_pos(root, "main_window", hive.theme_window);
}
}ãã®å€æŽ(远å )ã«ãããååã®ãŠã£ã³ããŠã®äœçœ®ãšå€§ããã§AviUtl2ãéãããã«ãªããŸã
