Difference between revisions of "LMDThemes GradientRenderer"

From LMD
Jump to: navigation, search
m
 
(33 intermediate revisions by one other user not shown)
Line 1: Line 1:
= The new gradient theme renderer =
 
 
 
== Overview ==
 
== Overview ==
  
=== New units ===
+
=== New units in LMDRtlx ===
  
The new gradient theme engine was intended to implement themes imitating Office 2007 look. Actually it allows to build and use a wider variety of themes. It uses universal and  
+
'''The new gradient theme engine''' was intended to implement themes imitating Office 2007/2010 look. Actually it allows to build and use a wider variety of themes. It uses universal and flexible architecture of gradient fillers which allows to combine complex configurations of gradients.
  
flexible architecture of gradient fillers which allows to combine complex configurations of gradients.
+
These configurations, from the simplest to complex are:<br>- Solid filler;<br>- Gradient filler;<br>- Composition of fillers (any number of rectangular areas);<br>- Mix of fillers, where each filler in a blend has its weight;<br>- Mix of composition of fillers.<br>
  
These configurations, from the simplest to complex are:<br>
+
In order to implement the new renderer, we added several new graphical units, which can also be used separately. These are: LMDFillers, LMDFigures, LMDGradientFrames.
- Solid filler;<br>
 
- Gradient filler;<br>
 
- Composition of fillers (any number of rectangular areas);<br>
 
- Mix of fillers, where each filler in a blend has its weight;<br>
 
- Mix of composition of fillers.<br>
 
 
 
In order to implement the new renderer, we added several new graphical units, which can also be used separately. These are:
 
LMDFillers, LMDFigures, LMDGradientFrames.
 
  
 
==== LMDFillers ====
 
==== LMDFillers ====
  
LMDFillers unit contains base TLMDFiller class and its descendants for painting surfaces and borders of figures: - TLMDSolidFiller (floodfills figure with given color);<br> - TLMDVerticalGradient, TLMDHorizontalGradient, TLMDEllipseFiller, TLMDRoundFiller, TLMDLineFiller, TLMDRectangleFiller, TLMDBandFiller (floodfills figure with a given gradient);<br> - TLMDCompositeFiller (floodfilles rectangular areas with given gradients);<br> - TLMDMixedFillers (floodfills figure with a blend of gradients).
+
LMDFillers unit contains base TLMDFiller class and its descendants for painting surfaces and borders of figures:<br>- TLMDSolidFiller (floodfills figure with given color);<br>- TLMDVerticalGradient, TLMDHorizontalGradient, TLMDEllipseFiller, TLMDRoundFiller, TLMDLineFiller, TLMDRectangleFiller, TLMDBandFiller (floodfills figure with a given gradient);<br>- TLMDCompositeFiller (floodfilles rectangular areas with given gradients);<br>- TLMDMixedFillers (floodfills figure with a blend of gradients).
  
 
==== LMDFigures ====
 
==== LMDFigures ====
  
LMDFigures unit contains TLMDFigure class and its descendants: -TLMDRectangle, TLMDCustomCutRectangle, TLMDRoundRectangle;<br> -TLMDLine;<br> -TLMDEllipse, TLMDCircle;<br> -TLMDUnionFigure, TLMDSubtractionFigure.
+
LMDFigures unit contains TLMDFigure class and its descendants:<br>-TLMDRectangle, TLMDCustomCutRectangle, TLMDRoundRectangle;<br>-TLMDLine;<br>-TLMDEllipse, TLMDCircle;<br>-TLMDUnionFigure, TLMDSubtractionFigure.
  
 
==== LMDGradientFrames ====
 
==== LMDGradientFrames ====
Line 33: Line 23:
 
-TLMDGradientRectFrame draws rectangular frames consisting of three parts (outer border, inner space, inner border). These frames can have three types of corners: rectangular,
 
-TLMDGradientRectFrame draws rectangular frames consisting of three parts (outer border, inner space, inner border). These frames can have three types of corners: rectangular,
  
round and line. Each corner of a frame can have its own cut type.<br>
+
round and line. Each corner of a frame can have its own cut type.<br>-TLMDGradientCircleFrame draws round frames consisting of three parts (outer border, inner space, inner border).<br>-TLMDGradientCmpFrame draws complex frames consisting of three sets of parts: outer borders parts, inner space parts and inner border parts, each set of parts consists of 4 sides and 4 corners. This class is not used for rendering Office2007-like themes.<br><br>
-TLMDGradientCircleFrame draws round frames consisting of three parts (outer border, inner space, inner border).<br>
+
 
-TLMDGradientCmpFrame draws complex frames consisting of three sets of parts: outer borders parts, inner space parts and inner border parts, each set of parts consists of 4 sides  
+
=== New units in LMD ThemesPack ===
  
and 4 corners. This class  is not used for rendering Office2007-like themes.<br>
+
The new renderer is implemented in LMDThemesGradientThemeBase unit which contains main base class TLMDBaseGradientThemeRenderer. The LMDThemesGradientThemeRenderer introduces no functionality - it is used for registering engine for using by application.<Br>
  
  
 
=== Functionality ===
 
=== Functionality ===
  
The new renderer  
+
The new renderer<br>- implements interface declared in TLMDThemeServices class (LMDThemes unit);<br>- allows to use Office2007-like themes (three built-in color schemes: blue, metallic, black);<br>- allows to get access to its settings via helper properties;<br>- allows to change colors and brightness for several elements at a time;<br>- can store themes in XML file;<br>- can read themes from XML file and from CAB file (if it contains XML theme file).<br>
- implements interface declared in TLMDThemeServices class (LMDThemes unit);  
 
- allows to use Office2007-like themes (three built-in color schemes: blue, metallic, black);
 
- allows to get access to its settings via helper properties;
 
- allows to change colors and brightness for several elements at a time;
 
- can store themes in XML file;
 
- can read themes from XML file and from CAB file (if it contains XML theme file).
 
  
 
=== Structure ===
 
=== Structure ===
  
 
Each themed element has two arrays of corresponding descriptors, array of fill descriptors and array of frame descriptors:<br>
 
Each themed element has two arrays of corresponding descriptors, array of fill descriptors and array of frame descriptors:<br>
 
+
<syntaxhighlight lang="delphi">ButtonFill: array[TThemedButton] of TLMDGradientThemeFillDescriptor;
<pre class="brush:delphi">
+
ButtonFrame: array[TThemedButton] of TLMDGradientThemeFrameDescriptor;</syntaxhighlight>
ButtonFill: array[TThemedButton] of TLMDGradientThemeFillDescriptor;
+
Also, themed element can have array of text descriptors, but in current version text descriptor is used only for setting colors of font in tab text (for teTab element).<br>A gradient theme descriptor is a record that consists of parameters section and filler section:
ButtonFrame: array[TThemedButton] of TLMDGradientThemeFrameDescriptor;
+
<syntaxhighlight lang="delphi">type
</pre>
+
TLMDGradientThemeFillDescriptor = record
 
 
Also, themed element can have array of text descriptors, but in current version text descriptor is used only for setting colors of font in tab text (for teTab element).<br>
 
A gradient theme descriptor is a record that consists of parameters section and filler section:
 
 
 
<pre class="brush:delphi">
 
type
 
  TLMDGradientThemeFillDescriptor = record
 
 
     Params: TLMDGradientThemeFillParams;
 
     Params: TLMDGradientThemeFillParams;
 
     Fillers: array[TLMDGradientFillPart] of TLMDFiller;
 
     Fillers: array[TLMDGradientFillPart] of TLMDFiller;
  end;
+
end;
  
 
type
 
type
  TLMDGradientThemeFrameDescriptor = record
+
TLMDGradientThemeFrameDescriptor = record
 
     Params: TLMDGradientThemeFrameParams;
 
     Params: TLMDGradientThemeFrameParams;
 
     Fillers: array[TLMDGradientSFramePart] of TLMDFiller;
 
     Fillers: array[TLMDGradientSFramePart] of TLMDFiller;
  end;
+
end;
</pre>
+
</syntaxhighlight>
 
+
A fill descriptor determines how element's inner area is painted, whereas a frame descriptor determines how element's frame is painted.<br>
A fill descriptor determines how element's inner surface is painted, whereas a frame descriptor determines how element's frame is painted.<br>
 
  
 
== Usage ==
 
== Usage ==
  
=== Loading and activating ===
+
=== Loading, activating and deactivating themes ===
  
Nothing was changed here: in order to use the new renderer you have to put a reference to LMDThemesGradientThemeRenderer unit somewhere in your application.
+
Nothing was changed here: in order to use the new renderer you have to put a reference to LMDThemesGradientThemeRenderer unit somewhere in your application. Initialization section of this unit registers renderer so that application can use it for painting controls with ThemeMode = ttmNative. When renderer is active, active theme and color scheme can be changed by loading theme from file
Initialization section of this unit registers renderer so that application can use it for painting controls with ThemeMode = ttmNative.
 
When renderer is active, active theme and color scheme can be changed by loading theme from file  
 
  
  LMDThemeServices.ActivateTheme('Office2007.cab', 'Metallic');
+
LMDThemeServices.ActivateTheme('Office2007.cab', 'Metallic');
  
 
or by activating built-in color scheme:
 
or by activating built-in color scheme:
  
  LMDThemeServices.ActivateColorScheme('Black');
+
LMDThemeServices.ActivateColorScheme('Black');
  
Usually you do not have to deactivate theme directly, it is performed automatically when needed.
 
  
Changing colors and other params in run-time
+
In order to deactivate native theme and switch to current system theme
  
=== Mass changing methods ===
+
 
 +
, simply call LMDThemeServices.DeactivateTheme method.
 +
 
 +
=== Changing colors and other params in run-time ===
 +
 
 +
==== Mass changing methods ====
  
 
There are three methods that allow to change colors for several themed elements/details at a time:
 
There are three methods that allow to change colors for several themed elements/details at a time:
<pre class="brush:delphi">
+
<syntaxhighlight lang="delphi">procedure ChangeBrightness(aPercent: integer; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = -1);
procedure ChangeBrightness(aPercent: integer; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = -1);
 
  
 
procedure ReplaceColor(aOldColor, aNewColor: TColor; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = -1);
 
procedure ReplaceColor(aOldColor, aNewColor: TColor; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = -1);
  
procedure SetNewColor(aNewColor: TColor; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = 0);
+
procedure SetNewColor(aNewColor: TColor; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = 0);</syntaxhighlight>
</pre>
 
 
Each of these methods walks through all fillers for given element, given detail name mask, fill or frame part and performs required change. <br>
 
Each of these methods walks through all fillers for given element, given detail name mask, fill or frame part and performs required change. <br>
  
Line 111: Line 87:
  
 
Examples:
 
Examples:
<pre class="brush:delphi">//walks through all fillers for teTab element, for details like 'ttTopTabItem*'  
+
<syntaxhighlight lang="delphi">//walks through all fillers for teTab element, for details like 'ttTopTabItem*'  
 
  //and sets new color for each FixedColors entry with index 0
 
  //and sets new color for each FixedColors entry with index 0
 
  SetNewColor($0000FFFF, [teTab], 'ttTopTabItemHot*', [gfpMain], [], 0);
 
  SetNewColor($0000FFFF, [teTab], 'ttTopTabItemHot*', [gfpMain], [], 0);
Line 119: Line 95:
  
 
  //Changes brightness of all colors:  
 
  //Changes brightness of all colors:  
  ChangeBrightness(-10, []);</pre>
+
  ChangeBrightness(-10, []);</syntaxhighlight>
 +
==== Direct access to colors and filler properties ====
  
=== Direct access to colors and filler properties ===
+
Properties like *FillFiller, *FrameFiller allow to get direct access to fillers. Using them requires knowledge of how the filler is structured. Filler structure can be browsed in XML file. For
 +
 
 +
Office2007-like themes a filler is usually either solid filler, vertical/horizontal/elliptic gradient, composite filler of a mixed filler.<br>
  
Properties like *FillFiller, *FrameFiller allow to get direct access to fillers. Using them requires knowledge of how the filler is structured. Filler structure can be browsed in XML file. For
+
For example, this is how we can change start gradient color for teTab element, detail ttTopTabItemHot:
 +
<syntaxhighlight lang="delphi">with CThemeRenderer do
 +
TLMDCompositeFiller(TLMDMixedFiller(TabFillFiller[ttTopTabItemHot, gfpMain]).Item[0]).Item[0].FixedColors[0]&nbsp;:= clRed;</syntaxhighlight>
 +
This is rather complex construction because the filler in this case is a mix of composite filler and elliptic gradient:
 +
<syntaxhighlight lang="xml">
 +
<Filler Class="TLMDMixedFiller" Part="gfpMain" ItemCount="2">
 +
    <UseRelativeUnits Value="1"/>
 +
    <Item Index="0" Weight="255">
 +
        <Filler Class="TLMDCompositeFiller" ItemCount="2">
 +
            <UseRelativeUnits Value="1"/>
 +
            <Item Index="0">
 +
                <FillerRect Left="0" Top="0" Right="100" Bottom="45"/>
 +
                <Filler Class="TLMDVerticalGradient">
 +
                    <Colors ColorCount="2">
 +
                        <Color0 Value="$00FEDDC4"/>
 +
                        <Color1 Value="clWhite"/>
 +
                    </Colors>
 +
                </Filler>
 +
            </Item>
 +
            <Item Index="1">
 +
                <FillerRect Left="0" Top="45" Right="100" Bottom="100"/>
 +
                <Filler Class="TLMDVerticalGradient">
 +
                    <Colors ColorCount="2">
 +
                        <Color0 Value="$00FEDDC4"/>
 +
                        <Color1 Value="clWhite"/>
 +
                    </Colors>
 +
                </Filler>
 +
            </Item>
 +
        </Filler>
 +
    </Item>
 +
    <Item Index="1" Weight="255">
 +
        <Filler Class="TLMDEllipseFiller">
 +
            <UseRelativeUnits Value="1"/>
 +
            <BasePoint X="50" Y="0"/>
 +
            <Axis1 Value="80"/>
 +
            <Axis2 Value="80"/>
 +
            <FirstAxisDirection X="1" Y="0"/>
 +
            <Colors ColorCount="2">
 +
                <Color0 Value="$00FEDDC4"/>
 +
                <Color1 Value="$0098D1E3"/>
 +
            </Colors>
 +
        </Filler>
 +
    </Item>
 +
</Filler>
 +
</syntaxhighlight>
  
Office2007-like themes a filler is usually either solid filler, vertical/horizontal/elliptic gradient, composite filler of a mixed filler.<br>
+
So, we have to take filler for main fill part (gfpMain index), ttTopTabItemHot detail:<br>
 +
<syntaxhighlight lang="delphi">TabFillFiller[ttTopTabItemHot, gfpMain]</syntaxhighlight>
 +
then cast it to TLMDMixedFiller and take the first item, which is a composite filler:
 +
<syntaxhighlight lang="delphi">TLMDMixedFiller( * ).Item[0])</syntaxhighlight>
 +
then cast it to TLMDCompositeFiller and take the first item which is a vertical gradient, and change the first color:
 +
<syntaxhighlight lang="delphi">TLMDCompositeFiller( * ).Item[0].FixedColors[0]&nbsp;:= clRed;</syntaxhighlight>
 +
 
 +
==== Changing other filler properties ====
 +
 
 +
Each filler has BasePoint property which determines the coordinate origin for filler. Example:<br>
 +
<syntaxhighlight lang="delphi">with CThemeRenderer do
 +
begin
 +
//This will change base point of ellipse gradient filler (bottom part of the filler)
 +
//Coordinates are relative to rectangle of the element: (100, 100) is
 +
//the bottom right corner
 +
TLMDCompositeFiller(ButtonFillFiller[tbPushButtonPressed, gfpMain]).Item[1].BasePoint&nbsp;:= Point(100, 100);
 +
TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[1].BasePoint&nbsp;:= Point(0, 100);
 +
end;</syntaxhighlight>
 +
=== Parameters - detailed description ===
 +
 
 +
Parameters section is a simple one for fill descriptors and rather complex for frame descriptors. However, each parameter is a byte.
 +
 
 +
==== Fill descriptors ====
 +
 
 +
Here we have one parameter: gflpRenderMode (prefix gflp: '''g'''radient '''f'''il'''l''' '''p'''arameter)
 +
<syntaxhighlight lang="delphi">type
 +
TLMDGradientThemeFillParam = (gflpRenderMode);</syntaxhighlight>
 +
    Bits 0..1: 0 - standard, 1 - sketch, 2 and 3 - reserved;
 +
    Bit 2 - antialiasing for gfpMain;
 +
    Bits 3..6 - antialiasing for gfpDeco1..gfpDeco4.
 +
    Standard value is 4: 0000 0010.
 +
 
 +
==== Frame descriptors ====
 +
 
 +
Here we have a lot of parameters (prefix gfrp: '''g'''radient '''fr'''ame '''p'''arameter).<br>Most of frame parameters relate to determining how corners of a frame should look. For custom cut rectangle, CutX and CutY are the values that, along with corner cut type, determine how corner looks. E.g. here is a round-cut corner with its CutX and CutY values:<br>[[Image:Cutxy.PNG|Image:cutxy.PNG]]
 +
 
 +
<br>Since there are three possible areas of a frame (outer border, inner space and inner border), each of which can have its own corners description, the number of parameters section of a frame descriptor is about 40:
 +
<syntaxhighlight lang="delphi">type
 +
TLMDGradientThemeFrameParam =
 +
(
 +
//gfrpRenderMode
 +
//bits 0..1: 0 - standard, 1 - sketch, 2 and 3 - reserved
 +
//bit 2: outerborder antialasing flag - 4
 +
//bit 3: outerborder soft edge flag - 8
 +
//bit 4: innerspace antialasing flag - 16
 +
//bit 5: innerspace soft edge flag - 32
 +
//bit 6: innerborder antialasing flag - 64
 +
//bit 7: innerborder soft edge flag - 128
 +
//---------------- bits 7654 3210
 +
//standard value is 84: 0101 0100
 +
gfrpRenderMode,
 +
 
 +
//determine what sides of the border should be drawn
 +
gfrpOuterBorderSides,
 +
gfrpInnerBorderSides,
  
==== Changing colors ====
+
//determine edge width - each of border areas can have edges. Not used for Office2007-like themes
 +
gfrpOuterBorderEdgeWidth,
 +
gfrpInnerBorderEdgeWidth,
 +
gfrpSpaceEdgeWidth,
  
For example, this is how we can change start gradient color for teTab element, detail ttTopTabItemHot:
+
//determine border areas width
 +
gfrpOuterBorderWidth, gfrpInnerBorderWidth,
 +
//determines gap width between border area and innerspace area
 +
gfrpOuterBorderGap, gfrpInnerBorderGap,
  
<pre class="brush:delphi">
+
//determine inner space widths
    with CThemeRenderer do
+
gfrpTopSpaceWidth, gfrpRightSpaceWidth,
        TLMDCompositeFiller(TLMDMixedFiller(TabFillFiller[ttTopTabItemHot, gfpMain]).Item[0]).Item[0].FixedColors[0] := clRed;
+
gfrpBottomSpaceWidth, gfrpLeftSpaceWidth,
</pre>
 
  
This is rather complex construction because the filler in this case is a mix of composite filler and elliptic gradient:
+
//determines how cut values are calculated
 +
//Possible values are
 +
//cvuBoth - both cut values are used
 +
//cvuXOnly - only CutX value is used
 +
//cvuYOnly - only CutY value is used
 +
//cvuMin - minimum of CutX and CutY values is used
 +
//cvuMax - maximum of CutX and CutY values is used
 +
//cvuAverage - average of CutX and CutY values is used
 +
gfrpCutValueUsage,
  
<pre class="brush:xml">
+
//determine inner and outer cut type for outer border
<FillDescriptor>
+
//Possible values are ctNone (rectangular corner), ctLine (line-cut corner), ctRound (rounded corner)
<Params>
+
gfrpOuterBorderInnerCutType, gfrpOuterBorderOuterCutType,
<gflpRenderMode Value="4"/>
 
</Params>
 
<Fillers>
 
<Filler Class="TLMDMixedFiller" Part="gfpMain" ItemCount="2">
 
<UseRelativeUnits Value="1"/>
 
<Item Index="0" Weight="255">
 
<Filler Class="TLMDCompositeFiller" ItemCount="2">
 
<UseRelativeUnits Value="1"/>
 
<Item Index="0">
 
<FillerRect Left="0" Top="0" Right="100" Bottom="45"/>
 
<Filler Class="TLMDVerticalGradient">
 
<Colors ColorCount="2">
 
<Color0 Value="$00FEDDC4"/>
 
<Color1 Value="clWhite"/>
 
</Colors>
 
</Filler>
 
</Item>
 
<Item Index="1">
 
<FillerRect Left="0" Top="45" Right="100" Bottom="100"/>
 
<Filler Class="TLMDVerticalGradient">
 
<Colors ColorCount="2">
 
<Color0 Value="$00FEDDC4"/>
 
<Color1 Value="clWhite"/>
 
</Colors>
 
</Filler>
 
</Item>
 
</Filler>
 
</Item>
 
<Item Index="1" Weight="255">
 
<Filler Class="TLMDEllipseFiller">
 
<UseRelativeUnits Value="1"/>
 
<BasePoint X="50" Y="0"/>
 
<Axis1 Value="80"/>
 
<Axis2 Value="80"/>
 
<FirstAxisDirection X="1" Y="0"/>
 
<Colors ColorCount="2">
 
<Color0 Value="$00FEDDC4"/>
 
<Color1 Value="$0098D1E3"/>
 
</Colors>
 
</Filler>
 
</Item>
 
</Filler>
 
</Fillers>
 
</FillDescriptor> 
 
</pre>
 
  
So, we have to take filler for main fill part (gfpMain index), ttTopTabItemHot detail:<br>
+
//CutX and CutY values for inner and outer corners of outer border
<pre>
+
gfrpOuterBorderInnerCutX, gfrpOuterBorderInnerCutY,
        TabFillFiller[ttTopTabItemHot, gfpMain]
+
gfrpOuterBorderOuterCutX, gfrpOuterBorderOuterCutY,
</pre>
 
  
then cast it to TLMDMixed filler and take the first item, which is a composite filler:
+
//value types for outer border cut values
<pre>
+
//Possible values are vtAbsolute, vtPercent
        TLMDMixedFiller( * ).Item[0])
+
gfrpOuterBorderInnerCutXValueType, gfrpOuterBorderInnerCutYValueType,
</pre>
+
gfrpOuterBorderOuterCutXValueType, gfrpOuterBorderOuterCutYValueType,
then cast it to TLMDCompositeFiller and take the first item which is a vertical gradient, and change the first color:
 
<pre>
 
        TLMDCompositeFiller( * ).Item[0].FixedColors[0] := clRed;
 
</pre>
 
  
 +
//determine inner and outer cut type for inner space
 +
gfrpInnerSpaceInnerCutType, gfrpInnerSpaceOuterCutType,
  
====Changing other filler properties====
+
//CutX and CutY values for inner and outer corners of inner space
 +
gfrpInnerSpaceInnerCutX, gfrpInnerSpaceInnerCutY,
 +
gfrpInnerSpaceOuterCutX, gfrpInnerSpaceOuterCutY,
  
Each filler has BasePoint property which determines the coordinate origin for filler.
+
//value types for inner space cut values
Example:<br>
+
gfrpInnerSpaceInnerCutXValueType, gfrpInnerSpaceInnerCutYValueType,
<pre class="brush:delphi">
+
gfrpInnerSpaceOuterCutXValueType, gfrpInnerSpaceOuterCutYValueType,
    with CThemeRenderer do
 
      begin
 
        //This will change base point of ellipse gradient filler (bottom part of the filler)
 
        //Coordinates are relative to rectangle of the element: (100, 100) is
 
        //the bottom right corner
 
        TLMDCompositeFiller(ButtonFillFiller[tbPushButtonPressed, gfpMain]).Item[1].BasePoint := Point(100, 100);
 
        TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[1].BasePoint := Point(0, 100);
 
      end;
 
</pre>
 
  
===Parameters - detailed description===
+
//determine inner and outer cut type for inner border
 +
gfrpInnerBorderOuterCutType, gfrpInnerBorderInnerCutType,
  
Parameters section is a simple one for fill descriptors and rather complex for frame descriptors. However, each parameter is a byte.
+
//CutX and CutY values for inner and outer corners of inner border
 +
gfrpInnerBorderOuterCutX, gfrpInnerBorderOuterCutY,
 +
gfrpInnerBorderInnerCutX, gfrpInnerBorderInnerCutY,
  
====Fill descriptors====
+
//value types for inner border cut values
 +
gfrpInnerBorderOuterCutXValueType, gfrpInnerBorderOuterCutYValueType,
 +
gfrpInnerBorderInnerCutXValueType, gfrpInnerBorderInnerCutYValueType);</syntaxhighlight>
  
Here we have one parameter: gflpRenderMode (prefix gflp: gradient fill parameter)
+
=== Code samples ===
  
<pre class="brush:delphi">
+
==== Delphi ====
type
+
''Changing outer border of a push button''<br>
   TLMDGradientThemeFillParam = (gflpRenderMode);
+
<syntaxhighlight lang="delphi">
</pre>
+
cThemeRenderer := TLMDBaseGradientThemeRenderer(LMDThemeServices.CurrentRenderer);
 +
with CThemeRenderer do
 +
   begin
 +
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderWidth] := 2;
 +
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderWidth] := 2;
 +
    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderWidth] := 2;
 +
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderWidth] := 2;
 +
  end;
 +
LMDThemeServices.ApplyThemeChange;
 +
</syntaxhighlight>
  
<pre>
+
''Changing outline of a push button''<br>
   Bits 0..1: 0 - standard, 1 - sketch, 2 and 3 - reserved
+
<syntaxhighlight lang="delphi">
  Bit  2 - antialisasing for gfpMain
+
with CThemeRenderer do
  Bits 3..6 - antialisasing for gfpDeco1..gfpDeco4
+
   begin
 
+
    //See full list of frame params in LMDThemesGradientThemeBase unit
  Standard value is 4: 0000 0010
+
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderOuterCutType] := LMDCornerCutToByte(cLineCutCorners);
</pre>
+
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderInnerCutType] := LMDCornerCutToByte(cLineCutCorners);
 +
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderOuterCutType] := LMDCornerCutToByte(cLineCutCorners);
 +
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderInnerCutType] := LMDCornerCutToByte(cLineCutCorners);
 +
    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderOuterCutType] := LMDCornerCutToByte(cLineCutCorners);
 +
    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderInnerCutType] := LMDCornerCutToByte(cLineCutCorners);
 +
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderOuterCutType] := LMDCornerCutToByte(cLineCutCorners);
 +
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderInnerCutType] := LMDCornerCutToByte(cLineCutCorners);
  
====Frame descriptors====
+
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderOuterCutX] := 6;
 +
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderInnerCutX] := 6;
 +
    ButtonFrameParam[tbPushButtonNormal, gfrpInnerBorderOuterCutX] := 7;
 +
    ButtonFrameParam[tbPushButtonNormal, gfrpInnerBorderInnerCutX] := 7;
  
Here we have a lot of parameters (prefix gfrp: gradient frame parameter)<br>
+
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderOuterCutX] := 6;
 +
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderInnerCutX] := 6;
 +
    ButtonFrameParam[tbPushButtonHot, gfrpInnerBorderOuterCutX] := 7;
 +
    ButtonFrameParam[tbPushButtonHot, gfrpInnerBorderInnerCutX] := 7;
  
<pre class="brush:delphi">
+
    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderOuterCutX] := 6;
type
+
     ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderInnerCutX] := 6;
  TLMDGradientThemeFrameParam =
+
    ButtonFrameParam[tbPushButtonPressed, gfrpInnerBorderOuterCutX] := 7;
     (
+
    ButtonFrameParam[tbPushButtonPressed, gfrpInnerBorderInnerCutX] := 7;
    //gfrpRenderMode
 
    //bits 0..1: 0 - standard, 1 - sketch, 2 and 3 - reserved
 
    //bit 2: outerborder antialasing flag - 4
 
    //bit 3: outerborder soft edge flag  - 8
 
    //bit 4: innerspace antialasing flag  - 16
 
    //bit 5: innerspace soft edge flag    - 32
 
    //bit 6: innerborder antialasing flag - 64
 
    //bit 7: innerborder soft edge flag  - 128
 
    //---------------- bits  7654 3210
 
    //standard value is 84:  0101 0100
 
    gfrpRenderMode,
 
  
      //determine what sides of the border should be drawn
+
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderOuterCutX] := 6;
      gfrpOuterBorderSides,
+
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderInnerCutX] := 6;
      gfrpInnerBorderSides,
+
    ButtonFrameParam[tbPushButtonDisabled, gfrpInnerBorderOuterCutX] := 7;
 +
    ButtonFrameParam[tbPushButtonDisabled, gfrpInnerBorderInnerCutX] := 7;
 +
  end;
 +
LMDThemeServices.ApplyThemeChange;
 +
</syntaxhighlight>
  
      //determine edge width - each of border areas can have edges. Not used for Office2007-like themes
+
''Changing base point of an elliptic gradient of a push button''<br>
      gfrpOuterBorderEdgeWidth,  
+
<syntaxhighlight lang="delphi">
      gfrpInnerBorderEdgeWidth,
+
with CThemeRenderer do
      gfrpSpaceEdgeWidth,
+
  begin
 +
    TLMDCompositeFiller(ButtonFillFiller[tbPushButtonPressed, gfpMain]).Item[1].BasePoint := Point(100, 100);
 +
    TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[1].BasePoint := Point(0, 100);
 +
  end;
 +
</syntaxhighlight>
  
       //determine border areas width
+
''Adding third gradient area for a push button''<br>
      gfrpOuterBorderWidth, gfrpInnerBorderWidth,
+
<syntaxhighlight lang="delphi">
      //determines gap width between border area and innerspace area
+
with CThemeRenderer do
      gfrpOuterBorderGap, gfrpInnerBorderGap,
+
  begin
 +
    with TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]) do
 +
       begin
 +
        Add(TLMDVerticalGradient.Create);
 +
        FillerRect[0] := Rect(0, 0, 100, 10);
 +
        FillerRect[1] := Rect(0, 10, 100, 80);
 +
        FillerRect[2] := Rect(0, 80, 100, 100);
 +
        Item[2].FixedColors[0] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[0].FixedColors[1];
 +
        Item[2].FixedColors[1] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[0].FixedColors[0];
 +
      end;
  
       //determine inner space widths
+
    with TLMDCompositeFiller(ButtonFillFiller[tbPushButtonPressed, gfpMain]) do
      gfrpTopSpaceWidth, gfrpRightSpaceWidth,
+
       begin
      gfrpBottomSpaceWidth, gfrpLeftSpaceWidth,
+
        Add(TLMDVerticalGradient.Create);
 +
        FillerRect[0] := Rect(0, 0, 100, 10);
 +
        FillerRect[1] := Rect(0, 10, 100, 85);
 +
        FillerRect[2] := Rect(0, 85, 100, 100);
 +
        Item[2].FixedColors[0] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[2].FixedColors[0];
 +
        Item[2].FixedColors[1] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[2].FixedColors[1];
 +
      end; 
  
       //determines how cut values are calculated
+
    with TLMDCompositeFiller(ButtonFillFiller[tbPushButtonNormal, gfpMain]) do
      //Possible values are
+
       begin
      //cvuBoth - both cut values are used
+
        Add(TLMDVerticalGradient.Create);
      //cvuXOnly - only CutX value is used
+
        FillerRect[0] := Rect(0, 0, 100, 10);
      //cvuYOnly  - only CutY value is used
+
        FillerRect[1] := Rect(0, 10, 100, 85);
       //cvuMin - minimum of CutX and CutY values is used
+
        FillerRect[2] := Rect(0, 85, 100, 100);
      //cvuMax - maximum of CutX and CutY values is used
+
        Item[2].FixedColors[0] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonNormal, gfpMain]).Item[0].FixedColors[1];
      //cvuAverage - average of CutX and CutY values is used
+
        Item[2].FixedColors[1] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonNormal, gfpMain]).Item[0].FixedColors[0];
      gfrpCutValueUsage,
+
       end;
 +
  end;
 +
</syntaxhighlight>
  
      //determine inner and outer cut type for outer border
+
==== C++ Builder ====
      //Possible values are ctNone (rectangular corner), ctLine (line-cut corner), ctRound (rounded corner)
+
''Changing hot tab colors of LMDPageControl''
      gfrpOuterBorderInnerCutType, gfrpOuterBorderOuterCutType,
+
<syntaxhighlight lang="cpp">
 +
  TLMDBaseGradientThemeRenderer *cThemeRenderer;
 +
  TLMDFiller *filler;
 +
  TLMDCompositeFiller *cfiller;
 +
  TLMDMixedFiller *mfiller;
  
      //CutX and CutY values for inner and outer corners of outer border
+
  cThemeRenderer = (TLMDBaseGradientThemeRenderer*)LMDThemeServices()->CurrentRenderer;
      gfrpOuterBorderInnerCutX, gfrpOuterBorderInnerCutY,
+
  cThemeRenderer->SetNewColor(
      gfrpOuterBorderOuterCutX, gfrpOuterBorderOuterCutY,
+
    0x0000FFFF,
 +
    Lmdthemescommontypes::TThemedElementSet() << teTab,
 +
    "ttTopTabItemHot",
 +
    TLMDGradientFillParts() << gfpMain,
 +
    Lmdgradientframes::TLMDGradientSimpleFramePartKinds(),
 +
    0
 +
  );
 +
  filler = cThemeRenderer->TabFillFiller[ttTopTabItemHot][gfpMain];
 +
  mfiller = (TLMDMixedFiller*)filler;
 +
  cfiller = (TLMDCompositeFiller*)(mfiller->Item[0]);
 +
  cfiller->Item[0]->FixedColors[0] = clRed;
 +
</syntaxhighlight>
  
      //value types for outer border cut values
+
== Screenshots ==
      //Possible values are vtAbsolute, vtPercent
 
      gfrpOuterBorderInnerCutXValueType, gfrpOuterBorderInnerCutYValueType,
 
      gfrpOuterBorderOuterCutXValueType, gfrpOuterBorderOuterCutYValueType,
 
  
      //determine inner and outer cut type for inner space
+
=== Predefined color schemes ===
      gfrpInnerSpaceInnerCutType, gfrpInnerSpaceOuterCutType,
 
  
      //CutX and CutY values for inner and outer corners of inner space
+
'''Blue'''<br>[[Image:Office2007blue.png|Image:office2007blue.png]]<br>'''Metallic'''<br>[[Image:Office2007metallic.png|Image:office2007metallic.png]]<br>'''Black'''<br>[[Image:Office2007black.png|Image:office2007black.png]]<br>
      gfrpInnerSpaceInnerCutX, gfrpInnerSpaceInnerCutY,
 
      gfrpInnerSpaceOuterCutX, gfrpInnerSpaceOuterCutY,
 
  
      //value types for inner space cut values
+
=== ElXTree, ElToolBar and LMDButtonBar ===
      gfrpInnerSpaceInnerCutXValueType, gfrpInnerSpaceInnerCutYValueType,
 
      gfrpInnerSpaceOuterCutXValueType, gfrpInnerSpaceOuterCutYValueType,
 
  
      //determine inner and outer cut type for inner border
+
'''With blue color scheme'''<br>[[Image:Office2007blue elpack.png|Image:office2007blue_elpack.png]]<br>'''With black color scheme'''<br>[[Image:Office2007black elpack.png|Image:office2007black_elpack.png]]<br>
      gfrpInnerBorderOuterCutType, gfrpInnerBorderInnerCutType,
 
  
      //CutX and CutY values for inner and outer corners of inner border
+
=== Changing colors at runtime ===
      gfrpInnerBorderOuterCutX, gfrpInnerBorderOuterCutY,
 
      gfrpInnerBorderInnerCutX, gfrpInnerBorderInnerCutY,
 
  
      //value types for inner border cut values
+
'''Third gradient area added for push buttons, tab colors modified'''<br>[[Image:Office2007blue changecolors.png|Image:office2007blue_changecolors.png]]<br>'''Base point changed for push buttons'''<br>[[Image:Office2007darkblue bpchanged.png|Image:office2007darkblue_bpchanged.png]]<br>'''Dark blue scheme (brightness -30%)'''<br>[[Image:Office2007darkblue moregrads.png|Image:office2007darkblue_moregrads.png]]<br>
      gfrpInnerBorderOuterCutXValueType, gfrpInnerBorderOuterCutYValueType,
 
      gfrpInnerBorderInnerCutXValueType, gfrpInnerBorderInnerCutYValueType);
 
</pre>
 

Latest revision as of 13:43, 18 August 2017

Overview

New units in LMDRtlx

The new gradient theme engine was intended to implement themes imitating Office 2007/2010 look. Actually it allows to build and use a wider variety of themes. It uses universal and flexible architecture of gradient fillers which allows to combine complex configurations of gradients.

These configurations, from the simplest to complex are:
- Solid filler;
- Gradient filler;
- Composition of fillers (any number of rectangular areas);
- Mix of fillers, where each filler in a blend has its weight;
- Mix of composition of fillers.

In order to implement the new renderer, we added several new graphical units, which can also be used separately. These are: LMDFillers, LMDFigures, LMDGradientFrames.

LMDFillers

LMDFillers unit contains base TLMDFiller class and its descendants for painting surfaces and borders of figures:
- TLMDSolidFiller (floodfills figure with given color);
- TLMDVerticalGradient, TLMDHorizontalGradient, TLMDEllipseFiller, TLMDRoundFiller, TLMDLineFiller, TLMDRectangleFiller, TLMDBandFiller (floodfills figure with a given gradient);
- TLMDCompositeFiller (floodfilles rectangular areas with given gradients);
- TLMDMixedFillers (floodfills figure with a blend of gradients).

LMDFigures

LMDFigures unit contains TLMDFigure class and its descendants:
-TLMDRectangle, TLMDCustomCutRectangle, TLMDRoundRectangle;
-TLMDLine;
-TLMDEllipse, TLMDCircle;
-TLMDUnionFigure, TLMDSubtractionFigure.

LMDGradientFrames

LMDGradientFrames unit contains TLMDBaseGradientFrame class and its descendants for painting different gradient frames:

-TLMDGradientRectFrame draws rectangular frames consisting of three parts (outer border, inner space, inner border). These frames can have three types of corners: rectangular,

round and line. Each corner of a frame can have its own cut type.
-TLMDGradientCircleFrame draws round frames consisting of three parts (outer border, inner space, inner border).
-TLMDGradientCmpFrame draws complex frames consisting of three sets of parts: outer borders parts, inner space parts and inner border parts, each set of parts consists of 4 sides and 4 corners. This class is not used for rendering Office2007-like themes.

New units in LMD ThemesPack

The new renderer is implemented in LMDThemesGradientThemeBase unit which contains main base class TLMDBaseGradientThemeRenderer. The LMDThemesGradientThemeRenderer introduces no functionality - it is used for registering engine for using by application.


Functionality

The new renderer
- implements interface declared in TLMDThemeServices class (LMDThemes unit);
- allows to use Office2007-like themes (three built-in color schemes: blue, metallic, black);
- allows to get access to its settings via helper properties;
- allows to change colors and brightness for several elements at a time;
- can store themes in XML file;
- can read themes from XML file and from CAB file (if it contains XML theme file).

Structure

Each themed element has two arrays of corresponding descriptors, array of fill descriptors and array of frame descriptors:

ButtonFill: array[TThemedButton] of TLMDGradientThemeFillDescriptor;
ButtonFrame: array[TThemedButton] of TLMDGradientThemeFrameDescriptor;

Also, themed element can have array of text descriptors, but in current version text descriptor is used only for setting colors of font in tab text (for teTab element).
A gradient theme descriptor is a record that consists of parameters section and filler section:

type
 TLMDGradientThemeFillDescriptor = record
    Params: TLMDGradientThemeFillParams;
    Fillers: array[TLMDGradientFillPart] of TLMDFiller;
 end;

type
 TLMDGradientThemeFrameDescriptor = record
    Params: TLMDGradientThemeFrameParams;
    Fillers: array[TLMDGradientSFramePart] of TLMDFiller;
 end;

A fill descriptor determines how element's inner area is painted, whereas a frame descriptor determines how element's frame is painted.

Usage

Loading, activating and deactivating themes

Nothing was changed here: in order to use the new renderer you have to put a reference to LMDThemesGradientThemeRenderer unit somewhere in your application. Initialization section of this unit registers renderer so that application can use it for painting controls with ThemeMode = ttmNative. When renderer is active, active theme and color scheme can be changed by loading theme from file

LMDThemeServices.ActivateTheme('Office2007.cab', 'Metallic');

or by activating built-in color scheme:

LMDThemeServices.ActivateColorScheme('Black');


In order to deactivate native theme and switch to current system theme


, simply call LMDThemeServices.DeactivateTheme method.

Changing colors and other params in run-time

Mass changing methods

There are three methods that allow to change colors for several themed elements/details at a time:

procedure ChangeBrightness(aPercent: integer; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = -1);

procedure ReplaceColor(aOldColor, aNewColor: TColor; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = -1);

procedure SetNewColor(aNewColor: TColor; aElements: TThemedElementSet = []; aDetailNameMask: string = ''; aFillParts: TLMDGradientFillParts = cGradientFillAllParts; aFrameParts: TLMDGradientSFrameParts = cGradientSFrameAllParts; aIndex: integer = 0);

Each of these methods walks through all fillers for given element, given detail name mask, fill or frame part and performs required change.

Note: ChangeBrightness and ReplaceColor apply change for all color entries starting from given index , whereas SetNewColor changes one color entry with a given index.

Examples:

//walks through all fillers for teTab element, for details like 'ttTopTabItem*' 
 //and sets new color for each FixedColors entry with index 0
 SetNewColor($0000FFFF, [teTab], 'ttTopTabItemHot*', [gfpMain], [], 0);

 //replaces each color entry with value $00F8E0CE by a new value $00F8D0BE
 ReplaceColor($00F8E0CE, $00F8D0BE);

 //Changes brightness of all colors: 
 ChangeBrightness(-10, []);

Direct access to colors and filler properties

Properties like *FillFiller, *FrameFiller allow to get direct access to fillers. Using them requires knowledge of how the filler is structured. Filler structure can be browsed in XML file. For

Office2007-like themes a filler is usually either solid filler, vertical/horizontal/elliptic gradient, composite filler of a mixed filler.

For example, this is how we can change start gradient color for teTab element, detail ttTopTabItemHot:

with CThemeRenderer do
 TLMDCompositeFiller(TLMDMixedFiller(TabFillFiller[ttTopTabItemHot, gfpMain]).Item[0]).Item[0].FixedColors[0]&nbsp;:= clRed;

This is rather complex construction because the filler in this case is a mix of composite filler and elliptic gradient:

<Filler Class="TLMDMixedFiller" Part="gfpMain" ItemCount="2">
    <UseRelativeUnits Value="1"/>
    <Item Index="0" Weight="255">
        <Filler Class="TLMDCompositeFiller" ItemCount="2">
            <UseRelativeUnits Value="1"/>
            <Item Index="0">
                <FillerRect Left="0" Top="0" Right="100" Bottom="45"/>
                <Filler Class="TLMDVerticalGradient">
                    <Colors ColorCount="2">
                        <Color0 Value="$00FEDDC4"/>
                        <Color1 Value="clWhite"/>
                    </Colors>
                </Filler>
            </Item>
            <Item Index="1">
                <FillerRect Left="0" Top="45" Right="100" Bottom="100"/>
                <Filler Class="TLMDVerticalGradient">
                    <Colors ColorCount="2">
                        <Color0 Value="$00FEDDC4"/>
                        <Color1 Value="clWhite"/>
                    </Colors>
                </Filler>
            </Item>
        </Filler>
    </Item>
    <Item Index="1" Weight="255">
        <Filler Class="TLMDEllipseFiller">
            <UseRelativeUnits Value="1"/>
            <BasePoint X="50" Y="0"/>
            <Axis1 Value="80"/>
            <Axis2 Value="80"/>
            <FirstAxisDirection X="1" Y="0"/>
            <Colors ColorCount="2">
                <Color0 Value="$00FEDDC4"/>
                <Color1 Value="$0098D1E3"/>
            </Colors>
        </Filler>
    </Item>
</Filler>

So, we have to take filler for main fill part (gfpMain index), ttTopTabItemHot detail:

TabFillFiller[ttTopTabItemHot, gfpMain]

then cast it to TLMDMixedFiller and take the first item, which is a composite filler:

TLMDMixedFiller( * ).Item[0])

then cast it to TLMDCompositeFiller and take the first item which is a vertical gradient, and change the first color:

TLMDCompositeFiller( * ).Item[0].FixedColors[0]&nbsp;:= clRed;

Changing other filler properties

Each filler has BasePoint property which determines the coordinate origin for filler. Example:

with CThemeRenderer do
 begin
 //This will change base point of ellipse gradient filler (bottom part of the filler)
 //Coordinates are relative to rectangle of the element: (100, 100) is
 //the bottom right corner
 TLMDCompositeFiller(ButtonFillFiller[tbPushButtonPressed, gfpMain]).Item[1].BasePoint&nbsp;:= Point(100, 100);
 TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[1].BasePoint&nbsp;:= Point(0, 100);
 end;

Parameters - detailed description

Parameters section is a simple one for fill descriptors and rather complex for frame descriptors. However, each parameter is a byte.

Fill descriptors

Here we have one parameter: gflpRenderMode (prefix gflp: gradient fill parameter)

type
 TLMDGradientThemeFillParam = (gflpRenderMode);
   Bits 0..1: 0 - standard, 1 - sketch, 2 and 3 - reserved;
   Bit 2 - antialiasing for gfpMain;
   Bits 3..6 - antialiasing for gfpDeco1..gfpDeco4.
   Standard value is 4: 0000 0010.

Frame descriptors

Here we have a lot of parameters (prefix gfrp: gradient frame parameter).
Most of frame parameters relate to determining how corners of a frame should look. For custom cut rectangle, CutX and CutY are the values that, along with corner cut type, determine how corner looks. E.g. here is a round-cut corner with its CutX and CutY values:
Image:cutxy.PNG


Since there are three possible areas of a frame (outer border, inner space and inner border), each of which can have its own corners description, the number of parameters section of a frame descriptor is about 40:

type
 TLMDGradientThemeFrameParam =
 ( 
 //gfrpRenderMode
 //bits 0..1: 0 - standard, 1 - sketch, 2 and 3 - reserved
 //bit 2: outerborder antialasing flag - 4
 //bit 3: outerborder soft edge flag - 8
 //bit 4: innerspace antialasing flag - 16
 //bit 5: innerspace soft edge flag - 32
 //bit 6: innerborder antialasing flag - 64
 //bit 7: innerborder soft edge flag - 128
 //---------------- bits 7654 3210
 //standard value is 84: 0101 0100
 gfrpRenderMode, 

 //determine what sides of the border should be drawn
 gfrpOuterBorderSides, 
 gfrpInnerBorderSides,

 //determine edge width - each of border areas can have edges. Not used for Office2007-like themes
 gfrpOuterBorderEdgeWidth, 
 gfrpInnerBorderEdgeWidth,
 gfrpSpaceEdgeWidth,

 //determine border areas width
 gfrpOuterBorderWidth, gfrpInnerBorderWidth,
 //determines gap width between border area and innerspace area
 gfrpOuterBorderGap, gfrpInnerBorderGap,

 //determine inner space widths
 gfrpTopSpaceWidth, gfrpRightSpaceWidth,
 gfrpBottomSpaceWidth, gfrpLeftSpaceWidth,

 //determines how cut values are calculated
 //Possible values are 
 //cvuBoth - both cut values are used
 //cvuXOnly - only CutX value is used
 //cvuYOnly - only CutY value is used
 //cvuMin - minimum of CutX and CutY values is used
 //cvuMax - maximum of CutX and CutY values is used 
 //cvuAverage - average of CutX and CutY values is used
 gfrpCutValueUsage,

 //determine inner and outer cut type for outer border
 //Possible values are ctNone (rectangular corner), ctLine (line-cut corner), ctRound (rounded corner)
 gfrpOuterBorderInnerCutType, gfrpOuterBorderOuterCutType,

 //CutX and CutY values for inner and outer corners of outer border
 gfrpOuterBorderInnerCutX, gfrpOuterBorderInnerCutY,
 gfrpOuterBorderOuterCutX, gfrpOuterBorderOuterCutY,

 //value types for outer border cut values
 //Possible values are vtAbsolute, vtPercent
 gfrpOuterBorderInnerCutXValueType, gfrpOuterBorderInnerCutYValueType,
 gfrpOuterBorderOuterCutXValueType, gfrpOuterBorderOuterCutYValueType,

 //determine inner and outer cut type for inner space
 gfrpInnerSpaceInnerCutType, gfrpInnerSpaceOuterCutType,

 //CutX and CutY values for inner and outer corners of inner space
 gfrpInnerSpaceInnerCutX, gfrpInnerSpaceInnerCutY,
 gfrpInnerSpaceOuterCutX, gfrpInnerSpaceOuterCutY,

 //value types for inner space cut values
 gfrpInnerSpaceInnerCutXValueType, gfrpInnerSpaceInnerCutYValueType,
 gfrpInnerSpaceOuterCutXValueType, gfrpInnerSpaceOuterCutYValueType,

 //determine inner and outer cut type for inner border
 gfrpInnerBorderOuterCutType, gfrpInnerBorderInnerCutType,

 //CutX and CutY values for inner and outer corners of inner border
 gfrpInnerBorderOuterCutX, gfrpInnerBorderOuterCutY,
 gfrpInnerBorderInnerCutX, gfrpInnerBorderInnerCutY,

 //value types for inner border cut values
 gfrpInnerBorderOuterCutXValueType, gfrpInnerBorderOuterCutYValueType,
 gfrpInnerBorderInnerCutXValueType, gfrpInnerBorderInnerCutYValueType);

Code samples

Delphi

Changing outer border of a push button

cThemeRenderer := TLMDBaseGradientThemeRenderer(LMDThemeServices.CurrentRenderer);
with CThemeRenderer do
  begin
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderWidth] := 2;
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderWidth] := 2;
    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderWidth] := 2;
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderWidth] := 2;
  end;
LMDThemeServices.ApplyThemeChange;

Changing outline of a push button

with CThemeRenderer do
  begin
    //See full list of frame params in LMDThemesGradientThemeBase unit
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderOuterCutType] := LMDCornerCutToByte(cLineCutCorners);
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderInnerCutType] := LMDCornerCutToByte(cLineCutCorners);
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderOuterCutType] := LMDCornerCutToByte(cLineCutCorners);
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderInnerCutType] := LMDCornerCutToByte(cLineCutCorners);
    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderOuterCutType] := LMDCornerCutToByte(cLineCutCorners);
    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderInnerCutType] := LMDCornerCutToByte(cLineCutCorners);
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderOuterCutType] := LMDCornerCutToByte(cLineCutCorners);
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderInnerCutType] := LMDCornerCutToByte(cLineCutCorners);

    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderOuterCutX] := 6;
    ButtonFrameParam[tbPushButtonNormal, gfrpOuterBorderInnerCutX] := 6;
    ButtonFrameParam[tbPushButtonNormal, gfrpInnerBorderOuterCutX] := 7;
    ButtonFrameParam[tbPushButtonNormal, gfrpInnerBorderInnerCutX] := 7;

    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderOuterCutX] := 6;
    ButtonFrameParam[tbPushButtonHot, gfrpOuterBorderInnerCutX] := 6;
    ButtonFrameParam[tbPushButtonHot, gfrpInnerBorderOuterCutX] := 7;
    ButtonFrameParam[tbPushButtonHot, gfrpInnerBorderInnerCutX] := 7;

    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderOuterCutX] := 6;
    ButtonFrameParam[tbPushButtonPressed, gfrpOuterBorderInnerCutX] := 6;
    ButtonFrameParam[tbPushButtonPressed, gfrpInnerBorderOuterCutX] := 7;
    ButtonFrameParam[tbPushButtonPressed, gfrpInnerBorderInnerCutX] := 7;

    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderOuterCutX] := 6;
    ButtonFrameParam[tbPushButtonDisabled, gfrpOuterBorderInnerCutX] := 6;
    ButtonFrameParam[tbPushButtonDisabled, gfrpInnerBorderOuterCutX] := 7;
    ButtonFrameParam[tbPushButtonDisabled, gfrpInnerBorderInnerCutX] := 7;
  end;
LMDThemeServices.ApplyThemeChange;

Changing base point of an elliptic gradient of a push button

with CThemeRenderer do
  begin
    TLMDCompositeFiller(ButtonFillFiller[tbPushButtonPressed, gfpMain]).Item[1].BasePoint := Point(100, 100);
    TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[1].BasePoint := Point(0, 100);
  end;

Adding third gradient area for a push button

with CThemeRenderer do
  begin
    with TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]) do
      begin
        Add(TLMDVerticalGradient.Create);
        FillerRect[0] := Rect(0, 0, 100, 10);
        FillerRect[1] := Rect(0, 10, 100, 80);
        FillerRect[2] := Rect(0, 80, 100, 100);
        Item[2].FixedColors[0] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[0].FixedColors[1];
        Item[2].FixedColors[1] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[0].FixedColors[0];
      end;

    with TLMDCompositeFiller(ButtonFillFiller[tbPushButtonPressed, gfpMain]) do
      begin
        Add(TLMDVerticalGradient.Create);
        FillerRect[0] := Rect(0, 0, 100, 10);
        FillerRect[1] := Rect(0, 10, 100, 85);
        FillerRect[2] := Rect(0, 85, 100, 100);
        Item[2].FixedColors[0] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[2].FixedColors[0];
        Item[2].FixedColors[1] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonHot, gfpMain]).Item[2].FixedColors[1];
      end;  

    with TLMDCompositeFiller(ButtonFillFiller[tbPushButtonNormal, gfpMain]) do
      begin
        Add(TLMDVerticalGradient.Create);
        FillerRect[0] := Rect(0, 0, 100, 10);
        FillerRect[1] := Rect(0, 10, 100, 85);
        FillerRect[2] := Rect(0, 85, 100, 100);
        Item[2].FixedColors[0] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonNormal, gfpMain]).Item[0].FixedColors[1];
        Item[2].FixedColors[1] := TLMDCompositeFiller(ButtonFillFiller[tbPushButtonNormal, gfpMain]).Item[0].FixedColors[0];
      end;
  end;

C++ Builder

Changing hot tab colors of LMDPageControl

  TLMDBaseGradientThemeRenderer *cThemeRenderer;
  TLMDFiller *filler;
  TLMDCompositeFiller *cfiller;
  TLMDMixedFiller *mfiller;

  cThemeRenderer = (TLMDBaseGradientThemeRenderer*)LMDThemeServices()->CurrentRenderer;
  cThemeRenderer->SetNewColor(
    0x0000FFFF,
    Lmdthemescommontypes::TThemedElementSet() << teTab,
    "ttTopTabItemHot",
    TLMDGradientFillParts() << gfpMain,
    Lmdgradientframes::TLMDGradientSimpleFramePartKinds(),
    0
  );
  filler = cThemeRenderer->TabFillFiller[ttTopTabItemHot][gfpMain];
  mfiller = (TLMDMixedFiller*)filler;
  cfiller = (TLMDCompositeFiller*)(mfiller->Item[0]);
  cfiller->Item[0]->FixedColors[0] = clRed;

Screenshots

Predefined color schemes

Blue
Image:office2007blue.png
Metallic
Image:office2007metallic.png
Black
Image:office2007black.png

ElXTree, ElToolBar and LMDButtonBar

With blue color scheme
Image:office2007blue_elpack.png
With black color scheme
Image:office2007black_elpack.png

Changing colors at runtime

Third gradient area added for push buttons, tab colors modified
Image:office2007blue_changecolors.png
Base point changed for push buttons
Image:office2007darkblue_bpchanged.png
Dark blue scheme (brightness -30%)
Image:office2007darkblue_moregrads.png