C++介面庫:在GDI上新增完全的alpha混合支援
阿新 • • 發佈:2018-12-27
做完了小型WCF之後,就是小型的WPF了。之前那個完全避免使用者大部分的錯誤使用導致的死鎖的方案還有一點點的問題,所以先休息一下,做做別的。為了在C++上重現一套類似WPF的工具,首先要解決繪圖部分。
繪圖的裝置當然是需要可切換的,於是用bridge模式定義了大量的介面,這些介面用來建立畫筆、畫刷、字型和圖形,然後圖形用樹的形式組織起來,最後放到一塊跟視窗連結的畫板上面,有需要的時候自動繪製。為了最快速地開始工作,我實現了一個GDI的繪圖裝置,以後有空再做DirectX的。但是我們知道GDI對alpha的支援是很弱的,只有一個叫alphablend的API用來貼bitmap,因此為了讓畫刷和畫筆都能夠支援alpha漸變、alpha點陣圖和alpha顏色,做了很多的工作。下面是截圖:
之所以不用GDI+僅僅是因為我不喜歡。下面是利用GDI組合出上面的效果的那部分程式碼:
1 #include "VL_GDIRenderer.h" 2 3 namespace vl
4 {
5 namespace interaction
6 {
7 namespace renderer
8 {
9 10 enum IndirectFillReason
11 {
12 ifrDirectFill,
13 ifrLinearGradient,
14 ifrAlphaLinearGradient,
15 ifrAlphaBitmap,
16 };
17 18 IndirectFillReason GetIndirectFillReason(const VL_IrBrushRec& Brush)
19 {
20 switch(Brush.BrushKind)
21 {
22 case VL_IrBrushRec::bkSolid:
23 if(Brush.MainColor.A!=255)
24 {
25 return ifrAlphaBitmap;
26 }
27 else 28 {
29 return ifrDirectFill;
30 }
31 case VL_IrBrushRec::bkLinearGradient:
32 if(Brush.MainColor.A!=255|| Brush.GradientColor.A!=255)
33 {
34 return ifrAlphaLinearGradient;
35 }
36 else 37 {
38 return ifrLinearGradient;
39 }
40 case VL_IrBrushRec::bkBitmap:
41 if(Brush.Bitmap->IsAlphaChannelBuilt())
42 {
43 return ifrAlphaBitmap;
44 }
45 else 46 {
47 return ifrDirectFill;
48 }
49 default:
50 return ifrDirectFill;
51 }
52 }
53 54 VBool IsBrushAlpha(const VL_IrBrushRec& Brush)
55 {
56 switch(GetIndirectFillReason(Brush))
57 {
58 case ifrAlphaBitmap:
59 returntrue;
60 case ifrAlphaLinearGradient:
61 returntrue;
62 default:
63 returnfalse;
64 }
65 }
66 67 VL_IrColor MixColor(const VL_IrColor& ColorA , const VL_IrColor& ColorB , VDouble Ratio)
68 {
69 return VL_IrColor(
70 ColorA.R+Round(Ratio*(ColorB.R-ColorA.R)),
71 ColorA.G+Round(Ratio*(ColorB.G-ColorA.G)),
72 ColorA.B+Round(Ratio*(ColorB.B-ColorA.B)),
73 ColorA.A+Round(Ratio*(ColorB.A-ColorA.A))
74 );
75 }
76 77 void SetColor(TRIVERTEX& Vertex , const VL_IrColor& Color)
78 {
79 Vertex.Red=Color.R<<8;
80 Vertex.Green=Color.G<<8;
81 Vertex.Blue=Color.G<<8;
82 Vertex.Alpha=Color.A<<8;
83 }
84 85 /*********************************************************************************************************
86 VL_GDIBrush
87 *********************************************************************************************************/ 88 89 VL_GDIBrush::VL_GDIBrush(VL_GDIFactory* Factory , const VL_IrBrushRec& Brush)
90 {
91 FFactory=Factory;
92 FInternalData=Brush;
93 switch(FInternalData.BrushKind)
94 {
95 case VL_IrBrushRec::bkSolid:
96 FBrush=new VL_WinBrush(RGB(FInternalData.MainColor.R,FInternalData.MainColor.G,FInternalData.MainColor.B));
97 if(FInternalData.MainColor.A!=255)
98 {
99 VL_WinBitmap::Ptr Bitmap=new VL_WinBitmap(32,32,VL_WinBitmap::vbb32Bits,true);
100 Bitmap->GetWinDC()->SetBrush(FBrush);
101 Bitmap->GetWinDC()->FillRect(0,0,32,32);
102 Bitmap->GenerateAlpha(FInternalData.MainColor.A);
103 Bitmap->BuildAlphaChannel();
104 FInternalData.Bitmap=Bitmap;
105 }
106 break;
107 case VL_IrBrushRec::bkLinearGradient:
108 break;
109 case VL_IrBrushRec::bkBitmap:
110 FBrush=new VL_WinBrush(FInternalData.Bitmap);
111 break;
112 default:
113 throw L"內部錯誤";
114 }
115 }
116 117 const VL_IrBrushRec& VL_GDIBrush::GetInternalData()
118 {
119 return FInternalData;
120 }
121 122 IVL_IrFactory* VL_GDIBrush::GetFactory()
123 {
124 return FFactory;
125 }
126 127 VL_WinBrush::Ptr VL_GDIBrush::GetGDIBrush()
128 {
129 return FBrush;
130 }
131 132 /*********************************************************************************************************
133 VL_GDIPen
134 *********************************************************************************************************/ 135 136 VL_GDIPen::VL_GDIPen(VL_GDIFactory* Factory , const VL_IrBrushRec& Brush , const VL_IrPenRec& Pen)
137 {
138 FFactory=Factory;
139 FInternalBrush=Brush;
140 FInternalPen=Pen;
141 142 VInt EndCap=0;
143 VInt Join=0;
144 switch(FInternalPen.EndCap)
145 {
146 case VL_IrPenRec::ecFlat:
147 EndCap=PS_ENDCAP_FLAT;
148 break;
149 case VL_IrPenRec::ecRound:
150 EndCap=PS_ENDCAP_ROUND;
151 break;
152 case VL_IrPenRec::ecSquare:
153 EndCap=PS_ENDCAP_SQUARE;
154 break;
155 default:
156 throw L"內部錯誤";
157 }
158 switch(FInternalPen.Join)
159 {
160 case VL_IrPenRec::jBevel:
161 Join=PS_JOIN_BEVEL;
162 break;
163 case VL_IrPenRec::jMiter:
164 Join=PS_JOIN_MITER;
165 break;
166 case VL_IrPenRec::jRound:
167 Join=PS_JOIN_ROUND;
168 break;
169 default:
170 throw L"內部錯誤";
171 }
172 173 switch(FInternalBrush.BrushKind)
174 {
175 case VL_IrBrushRec::bkSolid:
176 FPen=new VL_WinPen(PS_SOLID,EndCap,Join,FInternalPen.Weight,RGB(FInternalBrush.MainColor.R,FInternalBrush.MainColor.G,FInternalBrush.MainColor.B));
177 if(FInternalBrush.MainColor.A!=255)
178 {
179 VL_WinBrush::Ptr SolidBrush=new VL_WinBrush(RGB(FInternalBrush.MainColor.R,FInternalBrush.MainColor.G,FInternalBrush.MainColor.B));
180 VL_WinBitmap::Ptr Bitmap=new VL_WinBitmap(32,32,VL_WinBitmap::vbb32Bits,true);
181 Bitmap->GetWinDC()->SetBrush(SolidBrush);
182 Bitmap->GetWinDC()->FillRect(0,0,32,32);
183 Bitmap->GenerateAlpha(FInternalBrush.MainColor.A);
184 Bitmap->BuildAlphaChannel();
185 FInternalBrush.Bitmap=Bitmap;
186 }
187 break;
188 case VL_IrBrushRec::bkLinearGradient:
189 FPen=new VL_WinPen(PS_SOLID,EndCap,Join,FInternalPen.Weight,RGB(FInternalBrush.MainColor.R,FInternalBrush.MainColor.G,FInternalBrush.MainColor.B));
190 break;
191 case VL_IrBrushRec::bkBitmap:
192 FPen=new VL_WinPen(FInternalBrush.Bitmap,PS_SOLID,EndCap,Join,FInternalPen.Weight);
193 break;
194 default:
195 throw L"內部錯誤";
196 }
197 }
198 199 VL_GDIPen::~VL_GDIPen()
200 {
201 }
202 203 const VL_IrPenRec& VL_GDIPen::GetInternalPen()
204 {
205 return FInternalPen;
206 }
207 208 const VL_IrBrushRec& VL_GDIPen::GetInternalBrush()
209 {
210 return FInternalBrush;
211 }
212 213 IVL_IrFactory* VL_GDIPen::GetFactory()
214 {
215 return FFactory;
216 }
217 218 VL_WinPen::Ptr VL_GDIPen::GetGDIPen()
219 {
220 return FPen;
221 }
222 223 /*********************************************************************************************************
224 VL_GDIFont
225 *********************************************************************************************************/ 226 227 VL_GDIFont::VL_GDIFont(VL_GDIFactory* Factory , const VL_IrFontRec& Font)
228 {
229 FFactory=Factory;
230 FInternalData=Font;
231 FFont=new VL_WinFont(FInternalData.Name,FInternalData.Height,FInternalData.Width,0,0,FInternalData.Bold?900:400,FInternalData.Italic,FInternalData.Underline,FInternalData.StrikeOut,true);
232 }
233 234 VL_GDIFont::~VL_GDIFont()
235 {
236 }
237 238 const VL_IrFontRec& VL_GDIFont::GetInternalData()
239 {
240 return FInternalData;
241 }
242 243 IVL_IrFactory* VL_GDIFont::GetFactory()
244 {
245 return FFactory;
246 }
247 248 VL_WinFont::Ptr VL_GDIFont::GetGDIFont()
249 {
250 return FFont;
251 }
252 253 /*********************************************************************************************************
254 VL_GDIElement
255 *********************************************************************************************************/ 256 257 VL_WinDC* VL_GDIElement::GetDC()
258 {
259 return FCanvas?FCanvas->GetDC():0;
260 }
261 262 void VL_GDIElement::CreatePath()
263 {
264 FCanvas->GetDC()->BeginPath();
265 DrawForPath();
266 FCanvas->GetDC()->EndPath();
267 }
268 269 void VL_GDIElement::EnsureRegion()
270 {
271 if(FEnvironmentModified)
272 {
273 FEnvironmentModified=false;
274 if(FCanvas)
275 {
276 if(FPen)
277 {
278 FCanvas->GetDC()->SetPen(FPen->GetGDIPen());
279 CreatePath();
280 FCanvas->GetDC()->WidenPath();
281 FBorderRegion=FCanvas->GetDC()->RegionFromPath();
282 CreatePath();
283 FContentRegion=new VL_WinRegion(FCanvas->GetDC()->RegionFromPath(),FBorderRegion,RGN_DIFF);
284 }
285 else 286 {
287 CreatePath();
288 FContentRegion=FCanvas->GetDC()->RegionFromPath();
289 }
290 {
291 RECT Rect={0,0,0,0};
292 if(FBorderRegion)
293 {
294 Rect=FBorderRegion->GetBoundRect();
295 }
296 elseif(FContentRegion)
297 {
298 Rect=FContentRegion->GetBoundRect();
299 }
300 FElementRectangle=VL_IrRect(VL_IrPoint(Rect.left,Rect.top),VL_IrPoint(Rect.right-Rect.left,Rect.bottom-Rect.top));
301 }
302 {
303 RECT Rect={0,0,0,0};
304 if(FContentRegion)
305 {
306 Rect=FContentRegion->GetBoundRect();
307 }
308 FClientRectangle=VL_IrRect(VL_IrPoint(Rect.left,Rect.top),VL_IrPoint(Rect.right-Rect.left,Rect.bottom-Rect.top));
309 }
310 }
311 }
312 }
313 314 void VL_GDIElement::EnvironmentModified(VL_GDICanvas* Canvas)
315 {
316 if(FCanvas || Canvas)
317 {
318 FCanvas=Canvas;
319 FBorderRegion=0;
320 FContentRegion=0;
321 FElementRectangle=VL_IrRect();
322 FClientRectangle=VL_IrRect();
323 FEnvironmentModified=true;
324 for(VInt i=0;i<FChildren.GetCount();i++)
325 {
326 FChildren[i]->EnvironmentModified(Canvas);
327 }
328 }
329 }
330 331 VL_WinRegion::Ptr VL_GDIElement::EnterClip(VL_WinRegion::Ptr CurrentClip , VL_WinRegion::Ptr Region)
332 {
333 VL_WinRegion::Ptr Clip=CurrentClip?new VL_WinRegion(CurrentClip,Region,RGN_AND):Region;
334 FCanvas->GetDC()->ClipRegion(Clip);
335 return Clip;
336 }
337 338 void VL_GDIElement::LeaveClip(VL_WinRegion::Ptr CurrentClip)
339 {
340 if(CurrentClip)
341 {
342 FCanvas->GetDC()->ClipRegion(CurrentClip);
343 }
344 else 345 {
346 FCanvas->GetDC()->RemoveClip();
347 }
348 }
349 350 void VL_GDIElement::FillLinearGradient(VL_WinRegion::Ptr CurrentClip , VL_WinRegion::Ptr Region , const VL_IrBrushRec& Brush)
351 {
352 RECT BoundRect=EnterClip(CurrentClip,Region)->GetBoundRect();
353 VDouble Sin=sin(Brush.GradientAngle);
354 VDouble Cos=cos(Brush.GradientAngle);
355 if(Sin<0)
356 {
357 Cos=-Cos;
358 Sin=-Sin;
359 }
360 361 TRIVERTEX Vertices[4];
362 Vertices[0].x=BoundRect.left;
363 Vertices[0].y=BoundRect.top;
364 Vertices[1].x
繪圖的裝置當然是需要可切換的,於是用bridge模式定義了大量的介面,這些介面用來建立畫筆、畫刷、字型和圖形,然後圖形用樹的形式組織起來,最後放到一塊跟視窗連結的畫板上面,有需要的時候自動繪製。為了最快速地開始工作,我實現了一個GDI的繪圖裝置,以後有空再做DirectX的。但是我們知道GDI對alpha的支援是很弱的,只有一個叫alphablend的API用來貼bitmap,因此為了讓畫刷和畫筆都能夠支援alpha漸變、alpha點陣圖和alpha顏色,做了很多的工作。下面是截圖:
之所以不用GDI+僅僅是因為我不喜歡。下面是利用GDI組合出上面的效果的那部分程式碼:
1
4 {
5 namespace interaction
6 {
7 namespace renderer
8 {
9 10 enum IndirectFillReason
11 {
12 ifrDirectFill,
13 ifrLinearGradient,
14 ifrAlphaLinearGradient,
15
16 };
17 18 IndirectFillReason GetIndirectFillReason(const VL_IrBrushRec& Brush)
19 {
20 switch(Brush.BrushKind)
21 {
22 case VL_IrBrushRec::bkSolid:
23 if(Brush.MainColor.A!=255)
24 {
26 }
27 else 28 {
29 return ifrDirectFill;
30 }
31 case VL_IrBrushRec::bkLinearGradient:
32 if(Brush.MainColor.A!=255|| Brush.GradientColor.A!=255)
33 {
34 return ifrAlphaLinearGradient;
35 }
36 else 37 {
38 return ifrLinearGradient;
39 }
40 case VL_IrBrushRec::bkBitmap:
41 if(Brush.Bitmap->IsAlphaChannelBuilt())
42 {
43 return ifrAlphaBitmap;
44 }
45 else 46 {
47 return ifrDirectFill;
48 }
49 default:
50 return ifrDirectFill;
51 }
52 }
53 54 VBool IsBrushAlpha(const VL_IrBrushRec& Brush)
55 {
56 switch(GetIndirectFillReason(Brush))
57 {
58 case ifrAlphaBitmap:
59 returntrue;
60 case ifrAlphaLinearGradient:
61 returntrue;
62 default:
63 returnfalse;
64 }
65 }
66 67 VL_IrColor MixColor(const VL_IrColor& ColorA , const VL_IrColor& ColorB , VDouble Ratio)
68 {
69 return VL_IrColor(
70 ColorA.R+Round(Ratio*(ColorB.R-ColorA.R)),
71 ColorA.G+Round(Ratio*(ColorB.G-ColorA.G)),
72 ColorA.B+Round(Ratio*(ColorB.B-ColorA.B)),
73 ColorA.A+Round(Ratio*(ColorB.A-ColorA.A))
74 );
75 }
76 77 void SetColor(TRIVERTEX& Vertex , const VL_IrColor& Color)
78 {
79 Vertex.Red=Color.R<<8;
80 Vertex.Green=Color.G<<8;
81 Vertex.Blue=Color.G<<8;
82 Vertex.Alpha=Color.A<<8;
83 }
84 85 /*********************************************************************************************************
86 VL_GDIBrush
87 *********************************************************************************************************/ 88 89 VL_GDIBrush::VL_GDIBrush(VL_GDIFactory* Factory , const VL_IrBrushRec& Brush)
90 {
91 FFactory=Factory;
92 FInternalData=Brush;
93 switch(FInternalData.BrushKind)
94 {
95 case VL_IrBrushRec::bkSolid:
96 FBrush=new VL_WinBrush(RGB(FInternalData.MainColor.R,FInternalData.MainColor.G,FInternalData.MainColor.B));
97 if(FInternalData.MainColor.A!=255)
98 {
99 VL_WinBitmap::Ptr Bitmap=new VL_WinBitmap(32,32,VL_WinBitmap::vbb32Bits,true);
100 Bitmap->GetWinDC()->SetBrush(FBrush);
101 Bitmap->GetWinDC()->FillRect(0,0,32,32);
102 Bitmap->GenerateAlpha(FInternalData.MainColor.A);
103 Bitmap->BuildAlphaChannel();
104 FInternalData.Bitmap=Bitmap;
105 }
106 break;
107 case VL_IrBrushRec::bkLinearGradient:
108 break;
109 case VL_IrBrushRec::bkBitmap:
110 FBrush=new VL_WinBrush(FInternalData.Bitmap);
111 break;
112 default:
113 throw L"內部錯誤";
114 }
115 }
116 117 const VL_IrBrushRec& VL_GDIBrush::GetInternalData()
118 {
119 return FInternalData;
120 }
121 122 IVL_IrFactory* VL_GDIBrush::GetFactory()
123 {
124 return FFactory;
125 }
126 127 VL_WinBrush::Ptr VL_GDIBrush::GetGDIBrush()
128 {
129 return FBrush;
130 }
131 132 /*********************************************************************************************************
133 VL_GDIPen
134 *********************************************************************************************************/ 135 136 VL_GDIPen::VL_GDIPen(VL_GDIFactory* Factory , const VL_IrBrushRec& Brush , const VL_IrPenRec& Pen)
137 {
138 FFactory=Factory;
139 FInternalBrush=Brush;
140 FInternalPen=Pen;
141 142 VInt EndCap=0;
143 VInt Join=0;
144 switch(FInternalPen.EndCap)
145 {
146 case VL_IrPenRec::ecFlat:
147 EndCap=PS_ENDCAP_FLAT;
148 break;
149 case VL_IrPenRec::ecRound:
150 EndCap=PS_ENDCAP_ROUND;
151 break;
152 case VL_IrPenRec::ecSquare:
153 EndCap=PS_ENDCAP_SQUARE;
154 break;
155 default:
156 throw L"內部錯誤";
157 }
158 switch(FInternalPen.Join)
159 {
160 case VL_IrPenRec::jBevel:
161 Join=PS_JOIN_BEVEL;
162 break;
163 case VL_IrPenRec::jMiter:
164 Join=PS_JOIN_MITER;
165 break;
166 case VL_IrPenRec::jRound:
167 Join=PS_JOIN_ROUND;
168 break;
169 default:
170 throw L"內部錯誤";
171 }
172 173 switch(FInternalBrush.BrushKind)
174 {
175 case VL_IrBrushRec::bkSolid:
176 FPen=new VL_WinPen(PS_SOLID,EndCap,Join,FInternalPen.Weight,RGB(FInternalBrush.MainColor.R,FInternalBrush.MainColor.G,FInternalBrush.MainColor.B));
177 if(FInternalBrush.MainColor.A!=255)
178 {
179 VL_WinBrush::Ptr SolidBrush=new VL_WinBrush(RGB(FInternalBrush.MainColor.R,FInternalBrush.MainColor.G,FInternalBrush.MainColor.B));
180 VL_WinBitmap::Ptr Bitmap=new VL_WinBitmap(32,32,VL_WinBitmap::vbb32Bits,true);
181 Bitmap->GetWinDC()->SetBrush(SolidBrush);
182 Bitmap->GetWinDC()->FillRect(0,0,32,32);
183 Bitmap->GenerateAlpha(FInternalBrush.MainColor.A);
184 Bitmap->BuildAlphaChannel();
185 FInternalBrush.Bitmap=Bitmap;
186 }
187 break;
188 case VL_IrBrushRec::bkLinearGradient:
189 FPen=new VL_WinPen(PS_SOLID,EndCap,Join,FInternalPen.Weight,RGB(FInternalBrush.MainColor.R,FInternalBrush.MainColor.G,FInternalBrush.MainColor.B));
190 break;
191 case VL_IrBrushRec::bkBitmap:
192 FPen=new VL_WinPen(FInternalBrush.Bitmap,PS_SOLID,EndCap,Join,FInternalPen.Weight);
193 break;
194 default:
195 throw L"內部錯誤";
196 }
197 }
198 199 VL_GDIPen::~VL_GDIPen()
200 {
201 }
202 203 const VL_IrPenRec& VL_GDIPen::GetInternalPen()
204 {
205 return FInternalPen;
206 }
207 208 const VL_IrBrushRec& VL_GDIPen::GetInternalBrush()
209 {
210 return FInternalBrush;
211 }
212 213 IVL_IrFactory* VL_GDIPen::GetFactory()
214 {
215 return FFactory;
216 }
217 218 VL_WinPen::Ptr VL_GDIPen::GetGDIPen()
219 {
220 return FPen;
221 }
222 223 /*********************************************************************************************************
224 VL_GDIFont
225 *********************************************************************************************************/ 226 227 VL_GDIFont::VL_GDIFont(VL_GDIFactory* Factory , const VL_IrFontRec& Font)
228 {
229 FFactory=Factory;
230 FInternalData=Font;
231 FFont=new VL_WinFont(FInternalData.Name,FInternalData.Height,FInternalData.Width,0,0,FInternalData.Bold?900:400,FInternalData.Italic,FInternalData.Underline,FInternalData.StrikeOut,true);
232 }
233 234 VL_GDIFont::~VL_GDIFont()
235 {
236 }
237 238 const VL_IrFontRec& VL_GDIFont::GetInternalData()
239 {
240 return FInternalData;
241 }
242 243 IVL_IrFactory* VL_GDIFont::GetFactory()
244 {
245 return FFactory;
246 }
247 248 VL_WinFont::Ptr VL_GDIFont::GetGDIFont()
249 {
250 return FFont;
251 }
252 253 /*********************************************************************************************************
254 VL_GDIElement
255 *********************************************************************************************************/ 256 257 VL_WinDC* VL_GDIElement::GetDC()
258 {
259 return FCanvas?FCanvas->GetDC():0;
260 }
261 262 void VL_GDIElement::CreatePath()
263 {
264 FCanvas->GetDC()->BeginPath();
265 DrawForPath();
266 FCanvas->GetDC()->EndPath();
267 }
268 269 void VL_GDIElement::EnsureRegion()
270 {
271 if(FEnvironmentModified)
272 {
273 FEnvironmentModified=false;
274 if(FCanvas)
275 {
276 if(FPen)
277 {
278 FCanvas->GetDC()->SetPen(FPen->GetGDIPen());
279 CreatePath();
280 FCanvas->GetDC()->WidenPath();
281 FBorderRegion=FCanvas->GetDC()->RegionFromPath();
282 CreatePath();
283 FContentRegion=new VL_WinRegion(FCanvas->GetDC()->RegionFromPath(),FBorderRegion,RGN_DIFF);
284 }
285 else 286 {
287 CreatePath();
288 FContentRegion=FCanvas->GetDC()->RegionFromPath();
289 }
290 {
291 RECT Rect={0,0,0,0};
292 if(FBorderRegion)
293 {
294 Rect=FBorderRegion->GetBoundRect();
295 }
296 elseif(FContentRegion)
297 {
298 Rect=FContentRegion->GetBoundRect();
299 }
300 FElementRectangle=VL_IrRect(VL_IrPoint(Rect.left,Rect.top),VL_IrPoint(Rect.right-Rect.left,Rect.bottom-Rect.top));
301 }
302 {
303 RECT Rect={0,0,0,0};
304 if(FContentRegion)
305 {
306 Rect=FContentRegion->GetBoundRect();
307 }
308 FClientRectangle=VL_IrRect(VL_IrPoint(Rect.left,Rect.top),VL_IrPoint(Rect.right-Rect.left,Rect.bottom-Rect.top));
309 }
310 }
311 }
312 }
313 314 void VL_GDIElement::EnvironmentModified(VL_GDICanvas* Canvas)
315 {
316 if(FCanvas || Canvas)
317 {
318 FCanvas=Canvas;
319 FBorderRegion=0;
320 FContentRegion=0;
321 FElementRectangle=VL_IrRect();
322 FClientRectangle=VL_IrRect();
323 FEnvironmentModified=true;
324 for(VInt i=0;i<FChildren.GetCount();i++)
325 {
326 FChildren[i]->EnvironmentModified(Canvas);
327 }
328 }
329 }
330 331 VL_WinRegion::Ptr VL_GDIElement::EnterClip(VL_WinRegion::Ptr CurrentClip , VL_WinRegion::Ptr Region)
332 {
333 VL_WinRegion::Ptr Clip=CurrentClip?new VL_WinRegion(CurrentClip,Region,RGN_AND):Region;
334 FCanvas->GetDC()->ClipRegion(Clip);
335 return Clip;
336 }
337 338 void VL_GDIElement::LeaveClip(VL_WinRegion::Ptr CurrentClip)
339 {
340 if(CurrentClip)
341 {
342 FCanvas->GetDC()->ClipRegion(CurrentClip);
343 }
344 else 345 {
346 FCanvas->GetDC()->RemoveClip();
347 }
348 }
349 350 void VL_GDIElement::FillLinearGradient(VL_WinRegion::Ptr CurrentClip , VL_WinRegion::Ptr Region , const VL_IrBrushRec& Brush)
351 {
352 RECT BoundRect=EnterClip(CurrentClip,Region)->GetBoundRect();
353 VDouble Sin=sin(Brush.GradientAngle);
354 VDouble Cos=cos(Brush.GradientAngle);
355 if(Sin<0)
356 {
357 Cos=-Cos;
358 Sin=-Sin;
359 }
360 361 TRIVERTEX Vertices[4];
362 Vertices[0].x=BoundRect.left;
363 Vertices[0].y=BoundRect.top;
364 Vertices[1].x