|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionIf some of the styles above look familiar, they should. Many of them were derived from other articles on the CodeProject website. The Style Toolkit doesn’t use code from other articles, only definitions of things like colors, effects, border sizes, etc. The Style Toolkit does not predefine styles, in the same sense that C++ does not predefine classes; therefore, the number of styles that it can create is infinite. Of course, once you have created a style, similar to creating a class, you can reuse it, modify it, and share it. All the style components are created with layers, as if you were using a program like Photoshop; however, unlike Photoshop, all the layers are created programmatically. It doesn’t matter if it is a background, an indicator control, or an aqua button; they are all created by defining a sequence of graphics operations. BackgroundThe Style Toolkit uses GDI+; however, aside from the required initialization and the fact that it needs to compile and link correctly, it is transparent to the user. This article will not cover how to use and incorporate GDI+; if you are unfamiliar with it, read my GdipButton[^] article and other resources here on The Code Project. Usage Preview
To demonstrate the power and simplicity of the Style Toolkit, let’s look at the Teal Pane of the demo program. I removed the controls, because they have their own style objects. The motivation for this style came from the Vista Info Bar[^] article. The style above can be created with nine lines of code: void CStyleDemoDlg::CreateTealPane()
{
// create the stack
Stack TealPane(rect);
// set the OuterBorder params
TealPane.SetOuterBorder(2, Black);
// set the Inner Border params
TealPane.SetInnerBorder(2, RGB(135, 192, 185), RGB(109, 165, 168));
// 3 color gradient
TealPane.FillGrad3(HORIZ, RGB(9, 74, 116), RGB(32, 121, 140), RGB(5, 111, 90));
// add a top edge effect
TealPane.FillBar(rect, TOP_EDGE, 20, Clr(180,RGB(135, 192, 185)), Clr(0,White));
// add the shield image
TealPane.AddImage(CPoint(crnr.left, crnr.top),
IDR_SHIELD, _T("PNG"), 255);
// create a display string
CString str1(_T("Progress Styles\t\t\t Indicator Styles"));
// add the string
TealPane.AddString(str1, CPoint pt1(158, 35), RGB(148, 215, 255),
14, FONT_REG, L"Swiss")
// add to style
m_Style.AddStack(TealPane);
}
If you compare this to the Vista Info Bar source code, you can see how much more compact this is. Also, the Style Toolkit doesn’t use any external libraries, it only needs gdiplus.dll. The code above doesn’t actually do any graphics operations, it only defines them. A subsequent call to Styles, Stacks, and LayersDefinitions for the terminology used by the Style Toolkit are as follows:
Using the Style ToolkitCreating a style is just a matter of declaring a BOOL CStyleDemoDlg::OnEraseBkgnd(CDC* pDC)
{
CDialog::OnEraseBkgnd(pDevC);
CRect rect;
GetClientRect(rect);
Stack stack(rect);
Style style;
style.AddStack(stack);
stack.FillSolid(Green);
style.PaintStyle(pDC, rect);
return TRUE;
}
In practice, you wouldn’t declare the stacks and styles in the erase function; you would just call the The Backgrounds and Borders
BackgroundsWe have already seen how to create a background, let’s look at a few more. The background on the left is a JPEG image. You can use images in any format supported by GDI+, and they can also be partially transparent. The right hand side is a BordersA The left side of the image above is an example of a transition border. The outer edge is rectangular and the inner edge is a round rect. The predefined borders are just for convenience, they are easy to declare because their relative positions are fixed, so you only have to declare the width. You can also create borders without using the predefined ones, because a layer can also be any of the shapes above. The border on the right hand side in the above image was created with layers, by declaring a clipping region in the center and using gradient fills for the edges. Style ControlsThe initial version of the Style Toolkit supports button, edit and progress controls. More will be added as time permits. StyleProgressThe The
The default style is the Vista looking one in the upper left. If you don’t add any stacks to the control, it will create that style. The definitions for the default style came from Xasthom’s VistaProgressBar[^] article. You can change the colors of the default control by calling The second progress bar just uses a gradient layer for the bottom and an elliptical gradient layer for the top. The motivation for this style came from Kochise’s CSkinProgress[^] article. His control actually uses a PNG image and has a few hundred more features than mine. The top indicator bar doesn’t step the colored layer. It can’t because it would always be green to red, regardless of the position. It actually steps a clear layer on top of the colored layer which defines the clipping region. The bottom indicator was motivated by Hans Dietrich’s XGradientZoneBar[^] article, but I added an additional wrapping gradient to give it the hump effect. The arrows are StyleButtonThe At a minimum, you must call
The VistaStyle1 Pane shows most of the different states the button can have. The definitions for this button were roughly derived from Jose Manuel Menéndez Poó’s article WindowsVistaRenderer[^]. Only the top two buttons (a normal button and a check type button) are fully implemented, the other four are forced to an alternate state for illustration purposes. Implementing Styles for a ButtonI chose this button style for the demo program because of its complexity. The way to create these buttons is to separate them into their unique components, or stacks in the toolkit terminology. For example, most of the states share the same base, or share the same glow, etc. When creating the style states, we just assemble the correct pieces together. The After defining the different operations needed to create each stack (not shown here), we just assemble the different pieces needed for each of the button states. // create standard group
VBStd = VB1Base;
// create the hot group
VBHot = VB1Base2 + VB1Hover + VB1Glow;
// create the pressed group
VBPress = VB1Base2 + VB1Pressed + VB1Glow;
// create the alt group
VBAlt = VB1Base2 + VB1Checked + VB1Hover + VB1CheckedGlow;
After creating the different stacks, we just add them to a style and then load them into the More Button Styles
Buttons can be rectangular, elliptical, or rounded as shown here. The definitions for the aqua style buttons were derived from the The Aqualizer Strikes Back[^] article. The definitions for the Vista Style 2 buttons were derived from Xasthom’s Vista Style Button in C#[^] article. The arrow buttons don’t use styles; they use a PNG file for the standard image and allow the StyleEditThe Style Toolkit APIThe Style Toolkit API is defined in the Style.h file. All the API functions will take GDI or GDI+ type arguments. For example, you could pass Overloaded OperatorsThe stack1 = stack2;
The = operator is the copy constructor, and behaves as you would expect. The layers in a stack are STL vectors, and the copy constructor will copy all the vectors in addition to doing a few housekeeping tasks. Images, strings, and regions are separate vectors, which are also copied. stack1 += stack2;
The += operator in this example adds everything from stack1 = stack2 + stack3;
In this example, TemplatesTemplates are technically not part of the Style Toolkit, since you don’t need them to create styles. A template is just a mechanism that may be used to define, maintain, and share a style. A template in the Style Toolkit is not the same as a C++ template. A C++ template is used to apply a set of behaviors to many different things; a Style Toolkit template is more analogous to a wood working template, which is used to make many copies of the same thing. For example, if a program has ten buttons, a mechanism is needed to make multiple copies of the same style, without having to define it ten times. Since a style is just a data set, there are multiple ways you could go about creating a template. A style could be stored to an ASCII file or an XML file; however, I chose to use classes since it is a fairly simple method. In the class method, you just define a class, add some stacks or styles as member variables, and define all the layers in the constructor. See the Templates.h and Templates.cpp files for examples. ScopeYou may notice when looking though the code that stacks are never declared with the Even when a stack is declared as a member variable of a template class, the template classes themselves are temporary construction objects that are destroyed when they go out of scope. TransparencyThe bottom pane of the demo program demonstrates the use of transparency. All the components of a style can be anything from fully opaque to fully transparent. You can define the transparency of a color by using the Graphics EfficiencyStacks are actually only “painted” once — the first time that they are used. Once a stack has painted all of its layers, it creates a bitmap bounded by its frame. Any subsequent paint call to the stack just copies the bitmap to the device context. The exception to this is when the stack’s When the There is no practical limit to the number of layers and stacks you can have. Also, using the Style Toolkit is not slower than using GDI+ directly. The reason for this is because stacks and layers are really just nested loop counters of the How to Efficiently Use the Style ToolkitIn order to minimize paint operations, create different stacks for things that are dynamic versus static. For example, the progress control’s background never changes, so it has its own stack that only gets painted once. The foreground needs to be regenerated every time a step occurs, so it is in a separate stack. Any stack on top of a stack that has been marked for regeneration also needs to be marked for regeneration by the user. Even though an upper stack itself may not have changed, its background did, and therefore its bitmap is incorrect. The toolkit doesn’t do this automatically since it doesn’t keep track of, or care about, the relative positions of stacks. Needless to say, if a layer is completely covered by another layer or stack which is not at least partially transparent, then it should be removed. The stack code does not attempt to identify and/or remove any redundant paint operations. Issues and WorkaroundsGDI+ has a few issues that will create unexpected results.
Final CommentsThe demo programs were compiled with VC6 and VS2005, and tested on Windows XP. However, the Style Toolkit should work with any compiler and platform that supports GDI+. More controls and features will be added as time permits. If you would like a specific control added, request it in the message section. Revision HistoryVersion 1.2 - 2008 August 9
Version 1.0 - 2008 July 15
| ||||||||||||||||||||||