2009-02-10 18:37:48 +00:00
/*
Copyright ( C ) 2001 Kimmo Pekkola
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# pragma warning(disable: 4786)
# pragma warning(disable: 4996)
# include "MeterLine.h"
# include "Measure.h"
# include "Error.h"
# include <crtdbg.h>
# include <gdiplus.h>
using namespace Gdiplus ;
/*
* * CMeterLine
* *
* * The constructor
* *
*/
CMeterLine : : CMeterLine ( CMeterWindow * meterWindow ) : CMeter ( meterWindow )
{
m_Autoscale = false ;
m_HorizontalLines = false ;
m_HorizontalColor = 0 ;
m_CurrentPos = 0 ;
m_Flip = false ;
m_LineWidth = 1.0 ;
}
/*
* * ~ CMeterLine
* *
* * The destructor
* *
*/
CMeterLine : : ~ CMeterLine ( )
{
}
/*
* * Initialize
* *
* * create the buffer for the lines
* *
*/
void CMeterLine : : Initialize ( )
{
CMeter : : Initialize ( ) ;
std : : vector < Color > : : iterator i = m_Colors . begin ( ) ;
for ( ; i ! = m_Colors . end ( ) ; i + + )
{
m_AllValues . push_back ( std : : vector < double > ( ) ) ;
}
}
/*
* * ReadConfig
* *
* * Read the meter - specific configs from the ini - file .
* *
*/
void CMeterLine : : ReadConfig ( const WCHAR * section )
{
int i ;
WCHAR tmpName [ 256 ] ;
// Read common configs
CMeter : : ReadConfig ( section ) ;
CConfigParser & parser = m_MeterWindow - > GetParser ( ) ;
Added MeterStyle functionality:
Rainy, given the "issues" listed at the bottom of this comment, I leave it to you whether to create a build using this revision or use r208 for the build. I would like to start testing MeterStyle, but there are a few more things it needs work on.
What is MeterStyle?
MeterStyle
This will allow users to create CSS-like "Styles" for meters. This means that all the parameters of a meter can be defined in the style, and then many meters can use the style to eliminate copy / pasting the same parameters over and over on multiple meters. (Examples: FontColor=, FontSize= etc.)
How do I use it?
You will create a new [Section] (as many as you want) in the .ini. The section(s) can have any name.
[MyStringStyle]
Then you will tell Rainmeter that this is a "MeterStyle" and not a measure or meter
Style=Meter
Note: The "value" of the key "Style" can be anything. It can be used to add a description of the style if you like. Style=This style is for the AccuWeather part of this skin
It is however required, both to tell Rainmeter it is not a meter or measure and to have the MeterStyle routines parse it.
Then you define parameters you want to use in the style
FontColor=#FontColor#
FontFace=TheSansBold-Caps
FontSize=11
StringEffect=SHADOW
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Then in any or all meters, you just use
[MeterName]
Meter=STRING (or any other meter type)
MeterStyle=MyStringStyle
None of the parameters in the style are then required to be actually in the meter(s). They are "inherited" from the MeterStyle.
Note: This works and has had preliminary testing with dynamic variables like FontColor=[MeasureName] and regular variables like FontColor=#FontColor#. It doesn't matter if the [Variables] section or the [MeasureName] measure is before or after the [StyleName] in the .ini file.
What if I want to override a MeterStyle parameter on a meter?
Sure. Just put in any parameter with a value different from the one defined in the MeterStyle and the one in the meter will take presidence. All non-defined parameters will still use the MeterStyle value.
[MeterName]
Meter=STRING
MeterStyle=MyStringStyle
FontColor=100,100,100,50
What are these "known issues" you are on about?
This is still a bit of a work in progress. Right now you cannot define X or Y in a style. You can define W and H, but NOT for a STRING meter. You cannot define a "Transformation Matrix" in a style. MattKing will be looking into these tomorrow. W and H in a string meter is our top priority. We will also look at X and Y and hope for an easy solution. Transformation Matrix may have to come later.
2009-09-04 14:48:28 +00:00
int lineCount = parser . ReadInt ( section , L " LineCount " , parser . ReadInt ( m_StyleName . c_str ( ) , L " LineCount " , 1 ) ) ;
2009-02-10 18:37:48 +00:00
for ( i = 0 ; i < lineCount ; i + + )
{
if ( i = = 0 )
{
wcscpy ( tmpName , L " LineColor " ) ;
}
else
{
swprintf ( tmpName , L " LineColor%i " , i + 1 ) ;
}
Added MeterStyle functionality:
Rainy, given the "issues" listed at the bottom of this comment, I leave it to you whether to create a build using this revision or use r208 for the build. I would like to start testing MeterStyle, but there are a few more things it needs work on.
What is MeterStyle?
MeterStyle
This will allow users to create CSS-like "Styles" for meters. This means that all the parameters of a meter can be defined in the style, and then many meters can use the style to eliminate copy / pasting the same parameters over and over on multiple meters. (Examples: FontColor=, FontSize= etc.)
How do I use it?
You will create a new [Section] (as many as you want) in the .ini. The section(s) can have any name.
[MyStringStyle]
Then you will tell Rainmeter that this is a "MeterStyle" and not a measure or meter
Style=Meter
Note: The "value" of the key "Style" can be anything. It can be used to add a description of the style if you like. Style=This style is for the AccuWeather part of this skin
It is however required, both to tell Rainmeter it is not a meter or measure and to have the MeterStyle routines parse it.
Then you define parameters you want to use in the style
FontColor=#FontColor#
FontFace=TheSansBold-Caps
FontSize=11
StringEffect=SHADOW
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Then in any or all meters, you just use
[MeterName]
Meter=STRING (or any other meter type)
MeterStyle=MyStringStyle
None of the parameters in the style are then required to be actually in the meter(s). They are "inherited" from the MeterStyle.
Note: This works and has had preliminary testing with dynamic variables like FontColor=[MeasureName] and regular variables like FontColor=#FontColor#. It doesn't matter if the [Variables] section or the [MeasureName] measure is before or after the [StyleName] in the .ini file.
What if I want to override a MeterStyle parameter on a meter?
Sure. Just put in any parameter with a value different from the one defined in the MeterStyle and the one in the meter will take presidence. All non-defined parameters will still use the MeterStyle value.
[MeterName]
Meter=STRING
MeterStyle=MyStringStyle
FontColor=100,100,100,50
What are these "known issues" you are on about?
This is still a bit of a work in progress. Right now you cannot define X or Y in a style. You can define W and H, but NOT for a STRING meter. You cannot define a "Transformation Matrix" in a style. MattKing will be looking into these tomorrow. W and H in a string meter is our top priority. We will also look at X and Y and hope for an easy solution. Transformation Matrix may have to come later.
2009-09-04 14:48:28 +00:00
m_Colors . push_back ( parser . ReadColor ( section , tmpName , parser . ReadColor ( m_StyleName . c_str ( ) , tmpName , Color : : White ) ) ) ;
2009-02-10 18:37:48 +00:00
if ( i = = 0 )
{
wcscpy ( tmpName , L " Scale " ) ;
}
else
{
swprintf ( tmpName , L " Scale%i " , i + 1 ) ;
}
Added MeterStyle functionality:
Rainy, given the "issues" listed at the bottom of this comment, I leave it to you whether to create a build using this revision or use r208 for the build. I would like to start testing MeterStyle, but there are a few more things it needs work on.
What is MeterStyle?
MeterStyle
This will allow users to create CSS-like "Styles" for meters. This means that all the parameters of a meter can be defined in the style, and then many meters can use the style to eliminate copy / pasting the same parameters over and over on multiple meters. (Examples: FontColor=, FontSize= etc.)
How do I use it?
You will create a new [Section] (as many as you want) in the .ini. The section(s) can have any name.
[MyStringStyle]
Then you will tell Rainmeter that this is a "MeterStyle" and not a measure or meter
Style=Meter
Note: The "value" of the key "Style" can be anything. It can be used to add a description of the style if you like. Style=This style is for the AccuWeather part of this skin
It is however required, both to tell Rainmeter it is not a meter or measure and to have the MeterStyle routines parse it.
Then you define parameters you want to use in the style
FontColor=#FontColor#
FontFace=TheSansBold-Caps
FontSize=11
StringEffect=SHADOW
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Then in any or all meters, you just use
[MeterName]
Meter=STRING (or any other meter type)
MeterStyle=MyStringStyle
None of the parameters in the style are then required to be actually in the meter(s). They are "inherited" from the MeterStyle.
Note: This works and has had preliminary testing with dynamic variables like FontColor=[MeasureName] and regular variables like FontColor=#FontColor#. It doesn't matter if the [Variables] section or the [MeasureName] measure is before or after the [StyleName] in the .ini file.
What if I want to override a MeterStyle parameter on a meter?
Sure. Just put in any parameter with a value different from the one defined in the MeterStyle and the one in the meter will take presidence. All non-defined parameters will still use the MeterStyle value.
[MeterName]
Meter=STRING
MeterStyle=MyStringStyle
FontColor=100,100,100,50
What are these "known issues" you are on about?
This is still a bit of a work in progress. Right now you cannot define X or Y in a style. You can define W and H, but NOT for a STRING meter. You cannot define a "Transformation Matrix" in a style. MattKing will be looking into these tomorrow. W and H in a string meter is our top priority. We will also look at X and Y and hope for an easy solution. Transformation Matrix may have to come later.
2009-09-04 14:48:28 +00:00
m_ScaleValues . push_back ( parser . ReadFloat ( section , tmpName , parser . ReadFloat ( m_StyleName . c_str ( ) , tmpName , 1.0 ) ) ) ;
2009-02-10 18:37:48 +00:00
if ( i ! = 0 )
{
swprintf ( tmpName , L " MeasureName%i " , i + 1 ) ;
Added MeterStyle functionality:
Rainy, given the "issues" listed at the bottom of this comment, I leave it to you whether to create a build using this revision or use r208 for the build. I would like to start testing MeterStyle, but there are a few more things it needs work on.
What is MeterStyle?
MeterStyle
This will allow users to create CSS-like "Styles" for meters. This means that all the parameters of a meter can be defined in the style, and then many meters can use the style to eliminate copy / pasting the same parameters over and over on multiple meters. (Examples: FontColor=, FontSize= etc.)
How do I use it?
You will create a new [Section] (as many as you want) in the .ini. The section(s) can have any name.
[MyStringStyle]
Then you will tell Rainmeter that this is a "MeterStyle" and not a measure or meter
Style=Meter
Note: The "value" of the key "Style" can be anything. It can be used to add a description of the style if you like. Style=This style is for the AccuWeather part of this skin
It is however required, both to tell Rainmeter it is not a meter or measure and to have the MeterStyle routines parse it.
Then you define parameters you want to use in the style
FontColor=#FontColor#
FontFace=TheSansBold-Caps
FontSize=11
StringEffect=SHADOW
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Then in any or all meters, you just use
[MeterName]
Meter=STRING (or any other meter type)
MeterStyle=MyStringStyle
None of the parameters in the style are then required to be actually in the meter(s). They are "inherited" from the MeterStyle.
Note: This works and has had preliminary testing with dynamic variables like FontColor=[MeasureName] and regular variables like FontColor=#FontColor#. It doesn't matter if the [Variables] section or the [MeasureName] measure is before or after the [StyleName] in the .ini file.
What if I want to override a MeterStyle parameter on a meter?
Sure. Just put in any parameter with a value different from the one defined in the MeterStyle and the one in the meter will take presidence. All non-defined parameters will still use the MeterStyle value.
[MeterName]
Meter=STRING
MeterStyle=MyStringStyle
FontColor=100,100,100,50
What are these "known issues" you are on about?
This is still a bit of a work in progress. Right now you cannot define X or Y in a style. You can define W and H, but NOT for a STRING meter. You cannot define a "Transformation Matrix" in a style. MattKing will be looking into these tomorrow. W and H in a string meter is our top priority. We will also look at X and Y and hope for an easy solution. Transformation Matrix may have to come later.
2009-09-04 14:48:28 +00:00
m_MeasureNames . push_back ( parser . ReadString ( section , tmpName , parser . ReadString ( m_StyleName . c_str ( ) , tmpName , L " " ) . c_str ( ) , true , true ) ) ;
2009-02-10 18:37:48 +00:00
}
}
Added MeterStyle functionality:
Rainy, given the "issues" listed at the bottom of this comment, I leave it to you whether to create a build using this revision or use r208 for the build. I would like to start testing MeterStyle, but there are a few more things it needs work on.
What is MeterStyle?
MeterStyle
This will allow users to create CSS-like "Styles" for meters. This means that all the parameters of a meter can be defined in the style, and then many meters can use the style to eliminate copy / pasting the same parameters over and over on multiple meters. (Examples: FontColor=, FontSize= etc.)
How do I use it?
You will create a new [Section] (as many as you want) in the .ini. The section(s) can have any name.
[MyStringStyle]
Then you will tell Rainmeter that this is a "MeterStyle" and not a measure or meter
Style=Meter
Note: The "value" of the key "Style" can be anything. It can be used to add a description of the style if you like. Style=This style is for the AccuWeather part of this skin
It is however required, both to tell Rainmeter it is not a meter or measure and to have the MeterStyle routines parse it.
Then you define parameters you want to use in the style
FontColor=#FontColor#
FontFace=TheSansBold-Caps
FontSize=11
StringEffect=SHADOW
StringStyle=BOLD
StringAlign=LEFT
AntiAlias=1
Then in any or all meters, you just use
[MeterName]
Meter=STRING (or any other meter type)
MeterStyle=MyStringStyle
None of the parameters in the style are then required to be actually in the meter(s). They are "inherited" from the MeterStyle.
Note: This works and has had preliminary testing with dynamic variables like FontColor=[MeasureName] and regular variables like FontColor=#FontColor#. It doesn't matter if the [Variables] section or the [MeasureName] measure is before or after the [StyleName] in the .ini file.
What if I want to override a MeterStyle parameter on a meter?
Sure. Just put in any parameter with a value different from the one defined in the MeterStyle and the one in the meter will take presidence. All non-defined parameters will still use the MeterStyle value.
[MeterName]
Meter=STRING
MeterStyle=MyStringStyle
FontColor=100,100,100,50
What are these "known issues" you are on about?
This is still a bit of a work in progress. Right now you cannot define X or Y in a style. You can define W and H, but NOT for a STRING meter. You cannot define a "Transformation Matrix" in a style. MattKing will be looking into these tomorrow. W and H in a string meter is our top priority. We will also look at X and Y and hope for an easy solution. Transformation Matrix may have to come later.
2009-09-04 14:48:28 +00:00
m_Flip = 0 ! = parser . ReadInt ( section , L " Flip " , 0 ! = parser . ReadInt ( m_StyleName . c_str ( ) , L " Flip " , 0 ) ) ;
m_Autoscale = 0 ! = parser . ReadInt ( section , L " AutoScale " , 0 ! = parser . ReadInt ( m_StyleName . c_str ( ) , L " AutoScale " , 0 ) ) ;
m_LineWidth = parser . ReadFloat ( section , L " LineWidth " , parser . ReadFloat ( m_StyleName . c_str ( ) , L " LineWidth " , 1.0 ) ) ;
m_HorizontalLines = 0 ! = parser . ReadInt ( section , L " HorizontalLines " , 0 ! = parser . ReadInt ( m_StyleName . c_str ( ) , L " HorizontalLines " , 0 ) ) ;
m_HorizontalColor = parser . ReadColor ( section , L " HorizontalColor " , parser . ReadColor ( m_StyleName . c_str ( ) , L " HorizontalColor " , Color : : Black ) ) ; // This is left here for backwards compatibility
m_HorizontalColor = parser . ReadColor ( section , L " HorizontalLineColor " , parser . ReadColor ( m_StyleName . c_str ( ) , L " HorizontalLineColor " , m_HorizontalColor ) ) ; // This is what it should be
2009-02-10 18:37:48 +00:00
}
/*
* * Update
* *
* * Updates the value ( s ) from the measures .
* *
*/
bool CMeterLine : : Update ( )
{
if ( CMeter : : Update ( ) & & m_Measure )
{
// Collect the values
if ( ! m_Measure - > IsDisabled ( ) )
{
double value = m_Measure - > GetValue ( ) ;
2009-02-14 10:11:28 +00:00
if ( ( int ) m_AllValues [ 0 ] . size ( ) < m_W )
2009-02-10 18:37:48 +00:00
{
m_AllValues [ 0 ] . push_back ( value ) ;
}
else
{
m_AllValues [ 0 ] [ m_CurrentPos ] = value ;
}
}
int counter = 1 ;
std : : vector < CMeasure * > : : iterator i = m_Measures . begin ( ) ;
for ( ; i ! = m_Measures . end ( ) ; i + + )
{
double value = ( * i ) - > GetValue ( ) ;
2009-02-14 10:11:28 +00:00
if ( ( int ) m_AllValues [ counter ] . size ( ) < m_W )
2009-02-10 18:37:48 +00:00
{
m_AllValues [ counter ] . push_back ( value ) ;
}
else
{
m_AllValues [ counter ] [ m_CurrentPos ] = value ;
}
counter + + ;
}
m_CurrentPos + + ;
if ( m_CurrentPos > = m_W )
{
m_CurrentPos = 0 ;
}
return true ;
}
return false ;
}
/*
* * Draw
* *
* * Draws the meter on the double buffer
* *
*/
2009-07-27 11:48:57 +00:00
bool CMeterLine : : Draw ( Graphics & graphics )
2009-02-10 18:37:48 +00:00
{
2009-07-27 11:48:57 +00:00
if ( ! CMeter : : Draw ( graphics ) ) return false ;
2009-02-10 18:37:48 +00:00
double maxValue = 0.0 ;
int counter = 0 ;
// Find the maximum value
if ( m_Autoscale )
{
double newValue = 0 ;
std : : vector < std : : vector < double > > : : iterator i = m_AllValues . begin ( ) ;
counter = 0 ;
for ( ; i ! = m_AllValues . end ( ) ; i + + )
{
std : : vector < double > : : iterator j = ( * i ) . begin ( ) ;
for ( ; j ! = ( * i ) . end ( ) ; j + + )
{
newValue = max ( newValue , ( * j ) * m_ScaleValues [ counter ] ) ;
}
counter + + ;
}
// Scale the value up to nearest power of 2
maxValue = 2 ;
while ( maxValue < newValue & & maxValue ! = 0 )
{
maxValue * = 2 ;
}
}
else
{
if ( m_Measure )
{
maxValue = m_Measure - > GetMaxValue ( ) ;
std : : vector < CMeasure * > : : iterator i = m_Measures . begin ( ) ;
for ( ; i ! = m_Measures . end ( ) ; i + + )
{
maxValue = max ( maxValue , ( * i ) - > GetMaxValue ( ) ) ;
}
}
}
if ( maxValue = = 0.0 )
{
maxValue = 1.0 ;
}
int x = GetX ( ) ;
int y = GetY ( ) ;
// Draw the horizontal lines
if ( m_HorizontalLines )
{
// Calc the max number of lines we should draw
int maxLines = m_H / 4 ; // one line per 4 pixels is max
int numOfLines ;
// Check the highest power of 2 that fits in maxLines
int power = 2 ;
while ( power < maxLines )
{
power * = 2 ;
}
numOfLines = ( ( int ) maxValue % power ) + 1 ;
Pen pen ( m_HorizontalColor ) ;
REAL Y ;
for ( int j = 0 ; j < numOfLines ; j + + )
{
Y = ( REAL ) ( ( j + 1 ) * m_H / ( numOfLines + 1 ) ) ;
Y = y + m_H - Y - 1 ;
graphics . DrawLine ( & pen , ( REAL ) x , Y , ( REAL ) ( x + m_W - 1 ) , Y ) ; // GDI+
}
}
// Draw all the lines
counter = 0 ;
std : : vector < std : : vector < double > > : : iterator i = m_AllValues . begin ( ) ;
for ( ; i ! = m_AllValues . end ( ) ; i + + )
{
// Draw a line
int X = x ;
REAL Y = 0 ;
REAL oldY = 0 ;
int pos = m_CurrentPos ;
if ( pos > = m_W ) pos = 0 ;
Pen pen ( m_Colors [ counter ] , ( REAL ) m_LineWidth ) ;
for ( int j = 0 ; j < m_W ; j + + )
{
2009-02-14 10:11:28 +00:00
if ( pos < ( int ) ( * i ) . size ( ) )
2009-02-10 18:37:48 +00:00
{
Y = ( REAL ) ( ( * i ) [ pos ] * m_ScaleValues [ counter ] * ( m_H - 1 ) / maxValue ) ;
Y = min ( Y , m_H - 1 ) ;
Y = max ( Y , 0 ) ;
}
else
{
Y = 0 ;
}
if ( m_Flip )
{
Y = y + Y ;
}
else
{
Y = y + m_H - Y - 1 ;
}
if ( j ! = 0 )
{
graphics . DrawLine ( & pen , ( REAL ) X - 1 , oldY , ( REAL ) X , Y ) ; // GDI+
}
oldY = Y ;
X + + ;
pos + + ;
if ( pos > = m_W ) pos = 0 ;
}
counter + + ;
}
return true ;
}
/*
* * BindMeasure
* *
* * Overwritten method to handle the other measure bindings .
* *
*/
void CMeterLine : : BindMeasure ( std : : list < CMeasure * > & measures )
{
CMeter : : BindMeasure ( measures ) ;
std : : vector < std : : wstring > : : iterator j = m_MeasureNames . begin ( ) ;
for ( ; j ! = m_MeasureNames . end ( ) ; j + + )
{
// Go through the list and check it there is a secondary measure for us
std : : list < CMeasure * > : : iterator i = measures . begin ( ) ;
for ( ; i ! = measures . end ( ) ; i + + )
{
if ( _wcsicmp ( ( * i ) - > GetName ( ) , ( * j ) . c_str ( ) ) = = 0 )
{
m_Measures . push_back ( * i ) ;
break ;
}
}
if ( i = = measures . end ( ) )
{
throw CError ( std : : wstring ( L " The meter [ " ) + m_Name + L " ] cannot be bound with [ " + ( * j ) + L " ]! " , __LINE__ , __FILE__ ) ;
}
}
}