Invert windows forms vertical scrollbar - c#

I'm making a winforms app c#. The vertical scroll bar min value is at the top and max at the bottom, and scrolling down increases the value and vice versa. Is there a way to invert it, so that up is higher and down is lower.

You cannot actually "see" the value of the scroll bar just by looking at it, so, in other words, there is no actual difference between having min at the top, max at the bottom, and then just inverting the value when you access it:
private void ScrollBar_Scroll(object sender, ScrollEventArgs e)
{
// get the value (0 -> 100)
int value = scrollBar.Value;
// invert it (100 -> 0)
value = 100 - value;
// display it
someLabel.Text = value.ToString();
}
Of course, you can also override the VScrollBar class and add your own "inverted value" property:
public class InvertedScrollBar : VScrollBar
{
/// <summary>
/// Gets or sets the "inverted" scrollbar value.
/// </summary>
/// <value>The inverted value.</value>
public int InvertedValue
{
get
{
int offset = this.Value - this.Minimum;
return this.Maximum - offset;
}
set
{
int offset = this.Maximum - value;
this.Value = this.Minimum + offset;
}
}
}
Note that Maximum still has to be larger than Minimum when configuring it.

The values returned by the Value property of a ScrollBar go from scrollBar.Minimum to scrollBar.Maximum - scrollBar.LargeChange.
Thus if a scroll bar has Minimum of 5, Maximum of 15, and LargeChange (which doubles as the visible portion of the scrolling range) is 3, then the possible return values go from 5 to 12.
So, to invert the value, you actually want to use:
scrollBar.Minimum + scrollBar.Maximum - scrollBar.LargeChange - scrollBar.Value
(Normally you can think of Value as position of the left or top edge of the thumb. The formula above will give you the bottom edge of the thumb. If you still want the top edge (i.e. values going from 8 to 15 in the example above), then use:
scrollBar.Minimum + scrollBar.Maximum - scrollBar.Value

Related

Restore relative positions of views

EDIT: I forgot to describe my actual probem :D After orientation changes, portrait -> landscape or vice versa, the thumbs do not layout correctly. I want a thumb thats in the middle (width / 2) of the layout to remain at the middle of the layout after orientation change.
I'm trying to create a "range slider".
What I have is 2 simple views, that represent the two thumbs and a frame layout that represents the slider.
I'm laying out my two thumbs in the overridden OnLayout method, based on the width of the slider multiplied by the value of a thumb (between 0 and 1).
public class RangeSliderView : ViewGroup
{
public RangeSliderView(Context context) : base(context)
{
var thumbL = new Thumb(context);
var thumbR = new Thumb(context);
AddView(thumbL);
AddView(thumbR);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
if (changed)
{
//Get the width and height if not set yet
if (ThumbLeft.MeasuredWidth == 0 || ThumbLeft.MeasuredHeight == 0)
ThumbLeft.Measure(MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified), MeasureSpec.MakeMeasureSpec(b, MeasureSpecMode.AtMost));
if (ThumbRight.MeasuredWidth == 0 || ThumbRight.MeasuredHeight == 0)
ThumbRight.Measure(MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified), MeasureSpec.MakeMeasureSpec(b, MeasureSpecMode.AtMost));
//calculate width and the relative position of the thumbs
int width = r - l;
int thumbLeftX = (int)(width * lastProgressLeft); //last progresses are a value between 0 and 1
int thumbRightX = (int)(width * lastProgressRight);
//position the thumbs
ThumbLeft.Layout(l: l + thumbLeftX,
t: t,
r: l + thumbLeftX + ThumbLeft.MeasuredWidth,
b: ThumbLeft.MeasuredHeight);
ThumbRight.Layout(l: l + thumbRightX - ThumbRight.MeasuredWidth,
t: t,
r: l + thumbRightX,
b: ThumbLeft.MeasuredHeight);
}
}
}
The values really seem to be correct, in the landscape, the "r" value is bigger than in portrait. "l" is always 0 since the control is aligned to the left of my screen. The calculation seems correct, I tested moving one of the thumbs to the middle, so I can exactly see if thumbLeftX or thumbRightX are 50% of the width. It seemed correct.
I think the Layout(...) calls on the thumbs do not layout my thumbs reliably.
Is there a layout call that I'm missing?
Do I need to call other methods to re-layout my thumbs correctly?
Initially, the lastProgressLeft is 0 and the lastProgressRight is 1 (meaning thumb left should be at the left end of the slider, the right thumb at the right end of the slider. This works great, also on orientation changes, it looks correct.

Unity Dynamically Limiting a Slider in a Custom Editor Panel

I have attempted this in my panel already by working out the remaining amount of the total percentage and setting that as top limit of slider but that either seems to be inaccurate because my logic is wrong or it breaks the panel.
Currently the panel is scripted as shown below with the maximum the sliders can reach is 10 with a label showing me the total so i dont go over which is highly impractical.
public static int ammoxBoxesPercent = EditorPrefs.GetInt("Ammo");
public static int medicKitsPercent = EditorPrefs.GetInt("MedicKits");
public static int amountOfItemsPerZone = EditorPrefs.GetInt("Amount");
public static int totalPercentageVal;
public static int maxTotalValue = 10;
[MenuItem("Enviroment Controls/ Object Spawners Control Panel")]
private static void showEditor()
{
EditorWindow.GetWindow<ObjectSpawnersControlPanel>(false, "OBJ Spawners CP");
}
void OnGUI()
{
ammoxBoxesPercent = EditorGUILayout.IntSlider("Ammox Box Percent", ammoxBoxesPercent, 1, 10);
EditorPrefs.SetInt("Ammo", ammoxBoxesPercent);
medicKitsPercent = EditorGUILayout.IntSlider("Medic Kit Percent", medicKitsPercent, 1, 10);
EditorPrefs.SetInt("MedicKits", medicKitsPercent);
amountOfItemsPerZone = EditorGUILayout.IntSlider("Amount of Items Spawned at Each Zone", amountOfItemsPerZone, 1, 5);
EditorPrefs.SetInt("Amount", amountOfItemsPerZone);
totalPercentageVal = medicKitsPercent + ammoxBoxesPercent;
EditorGUILayout.LabelField ("Total Percentage so far : " + totalPercentageVal.ToString() + "0");
EditorGUILayout.LabelField ("Total must not go above 100");
}
The goal is to have it so when i set the first slider to say 6 i then set the limit of second slider to 4 because the percentage limit is 10 (representing 100 percent in my case)
Anybody know i decent method to achieve this?
Fairly easy. Just calculate 10 - ammoxBoxesPercent and use that as the max value for your IntSlider for medicKitsPercent.
One thing you'd want to do is to set the lower limit for medicKitsPercent to 0, so in case you hit 10 on ammoxBoxesPercent (Since you want the total to be 10 at max)
medicKitsPercent = EditorGUILayout.IntSlider("Medic Kit Percent", medicKitsPercent, 0, maxTotalValue - ammoxBoxesPercent);

Percent of Value graph in DevExpress Grid Cell

I need to represent a percent of value as a graph in DevExpress grid cell. I am able to paint using DrawLine but my problem is as soon as the percent value is equal to greater than 1 it is treated as 100% in this code. Please find the code below, As shown in the screenshot, 3.59 should be shown less than 8.35! Please help.
private void CustomDrawCell(object sender, RowCellCustomDrawEventArgs args)
{
args.Appearance.DrawBackground(args.Graphics, args.Cache, args.Bounds);
if (column != null)
{
int penSize = args.Bounds.Height * 2 / 3;
double value = GetValue(); // This is the value against which I have to display the graph, its in %.
int left = args.Bounds.Left;
int middle = args.Bounds.Height / 2 + args.Bounds.Top;
int width = args.Bounds.Width;
int right = (int)(left + width * value);
args.Graphics.DrawLine(new Pen(Color.Green, penSize), left, middle, right, middle);
}
args.Handled = true;
}
int right = (int)(left + width * value);
This code calculates the bar length correctly only if the value is between 0 and 1. If values are between 0 and 100 or between 0 and 10, you need to divide the result of multiplying by 100 or 10 correspondingly.
int right = (int)(left + width * value / 100);
By the way, it is not necessary to puzzle over custom drawing, because you are using XtraGrid. There is the RepositoryItemProgressBar component, which can be embedded into XtraGrid cell. It displays the line according to the cell value and allows you to define the maximum and minimum value, so that the line is most exactly visualize the cell value. Read this article to learn how to assign editors to columns: Assigning Editors to Columns and Card Fields

Calculating ScrollBar scroll percent; height of ScrollBar "bar"?

I am trying to determine the percentage value of a scroll bar in response to its OnScroll event, though I am having a difficult time determining the actual percentage. I would figure it should be as simple as doing the ratio of the current scroll value divided by the maximum value. Though this produces odd results.
void ThePanel_Scroll(object sender, ScrollEventArgs e)
{
if (e.ScrollOrientation == ScrollOrientation.VerticalScroll)
{
double scrollPercent = (double)e.NewValue / (double)ThePanel.VerticalScroll.Maximum;
Console.Out.WriteLine("Max: " + ThePanel.VerticalScroll.Maximum + " Min: " + ThePanel.VerticalScroll.Minimum);
Console.Out.WriteLine("OldVal: " + e.OldValue + " NewVal: " + e.NewValue + " Val: " + ThePanel.VerticalScroll.Value);
Console.Out.WriteLine("CurPer: " + scrollPercent);
}
}
When running this code, and scrolling the bar all the way to the maximum position, I might get some output like so
Max: 529 Min: 0
OldVal: 170 NewVal: 170 Val: 170
CurPer: 0.321361058601134
Even though the scroll bar is at a maximum position its Value is not. I assume the reason is that the Value is based off of the top of the scroll bar. My problem is that I cannot determine the height/size of the scroll bar "bar" itself, to calculate a proper percentage.
Is the proper way to determine the percent based on using the height of the bar along with the Value, or am I missing something else? If it is based off the height, how to I determine that? Reading through the VScrollProperties MSDN there is nothing there that would tell me the height of the bar itself.
There is an inherent ambiguity in the scrollbar position due to the non-zero thumb height. Which side of the thumb do you consider the "active" side? Windows doesn't help you deal with that, it suddenly switches over from one side to another when the thumb gets close to the maximum position. If you don't compensate for that then you'll lose a portion of the range.
The workaround is to take the sting out that flipping behavior and apply your own effective maximum. Like this:
private void panel1_Scroll(object sender, ScrollEventArgs e) {
if (e.ScrollOrientation == ScrollOrientation.VerticalScroll) {
var max = panel1.VerticalScroll.Maximum - panel1.VerticalScroll.LargeChange;
var pos = Math.Min(max, e.NewValue);
var percentage = 100.0 * pos / max;
// etc...
}
}
You can calculate the vertical scroll position in percent like this:
int percent_v = (int) Math.Min(100f * container.VerticalScroll.Value /
(content.Height - container.ClientSize.Height), 100);
Here the Container would be the Panel and the content maybe a Picturebox or whatever else you have placed inside.
I looks a bit weird and it is. When scrolled to its maximum, the value is not the real maximum but is reduced by the containing controls's height.
For horizontal scrolling the same applies.
Disclaimer: this is what I found by testing; I never saw it documented anywhere.

Rounding up for a Graph Maximum

I'm graphing some statistics which can be percentages, currency values or plain numbers.
I need to set the maximum value of the graph control's axis to a nice, round number just a bit above the maximum value in the data set. (The graph control's default value is not what I want).
Two things to note:
The value I set for the axis maximum should be minimum 5% above the dataset's maximum value (the less above this the better).
I have 4 horizontal lines above the 0 Y-axis; so ideally the Y-axis maximum should divide nicely by 4.
Sample data might be:
200%, 100%, 100%, 100%, 75%, 50%, 9%
In this case, 220% would be acceptable as the maximum value.
$3500161, $1825223, $1671232, $110112
In this case, $3680000 might be ok. Or $3700000 I suppose.
Can anyone suggest a nice formula for doing this? I might need to adjust settings, like the 5% margin might be changed to 10%, or I might need to change the 4 horizontal lines to 5.
Here is the code I use to create graph axes.
/// <summary>
/// Axis scales a min/max value appropriately for the purpose of graphs
/// <remarks>Code taken and modified from http://peltiertech.com/WordPress/calculate-nice-axis-scales-in-excel-vba/</remarks>
/// </summary>
public struct Axis
{
public readonly float min_value;
public readonly float max_value;
public readonly float major_step;
public readonly float minor_step;
public readonly int major_count;
public readonly int minor_count;
/// <summary>
/// Initialize Axis from range of values.
/// </summary>
/// <param name="x_min">Low end of range to be included</param>
/// <param name="x_max">High end of range to be included</param>
public Axis(float x_min, float x_max)
{
//Check if the max and min are the same
if(x_min==x_max)
{
x_max*=1.01f;
x_min/=1.01f;
}
//Check if dMax is bigger than dMin - swap them if not
if(x_max<x_min)
{
float temp = x_min;
x_min = x_max;
x_max = temp;
}
//Make dMax a little bigger and dMin a little smaller (by 1% of their difference)
float delta=(x_max-x_min)/2;
float x_mid=(x_max+x_min)/2;
x_max=x_mid+1.01f*delta;
x_min=x_mid-1.01f*delta;
//What if they are both 0?
if(x_max==0&&x_min==0)
{
x_max=1;
}
//This bit rounds the maximum and minimum values to reasonable values
//to chart. If not done, the axis numbers will look very silly
//Find the range of values covered
double pwr=Math.Log(x_max-x_min)/Math.Log(10);
double scl=Math.Pow(10, pwr-Math.Floor(pwr));
//Find the scaling factor
if(scl>0&&scl<=2.5)
{
major_step=0.2f;
minor_step=0.05f;
}
else if(scl>2.5&&scl<5)
{
major_step=0.5f;
minor_step=0.1f;
}
else if(scl>5&&scl<7.5)
{
major_step=1f;
minor_step=0.2f;
}
else
{
major_step=2f;
minor_step=0.5f;
}
this.major_step=(float)(Math.Pow(10, Math.Floor(pwr))*major_step);
this.minor_step=(float)(Math.Pow(10, Math.Floor(pwr))*minor_step);
this.major_count=(int)Math.Ceiling((x_max-x_min)/major_step);
this.minor_count=(int)Math.Ceiling((x_max-x_min)/minor_step);
int i_1=(int)Math.Floor(x_min/major_step);
int i_2=(int)Math.Ceiling(x_max/major_step);
this.min_value=i_1*major_step;
this.max_value=i_2*major_step;
}
public float[] MajorRange
{
get
{
float[] res=new float[major_count+1];
for(int i=0; i<res.Length; i++)
{
res[i]=min_value+major_step*i;
}
return res;
}
}
public float[] MinorRange
{
get
{
float[] res=new float[minor_count+1];
for(int i=0; i<res.Length; i++)
{
res[i]=min_value+minor_step*i;
}
return res;
}
}
}
You can the nice max_value and min_value as calculated from the initialized for Axis given the mathematical min. max. values in x_min and x_max.
Example:
new Axis(0,3500161) calculates max_value = 4000000.0
new Axis(0,1825223) calculates max_value = 2000000.0
new Axis(0,1671232) calculates max_value = 1800000.0
new Axis(0, 110112) calculates max_value = 120000.0
For your 1st query use:
DataView data = new DataView(dt);
string strTarget = dt.Compute("MAX(target)", string.Empty).ToString();// target is your column name.
int tTarget = int.Parse(strTarget.Equals("") ? "0" : strTarget); // Just in case if your string is empty.
myChart.ChartAreas[0].AxisY.Maximum = myChart.ChartAreas[0].AxisY2.Maximum = Math.Ceiling(tTarget * 1.1); // This will give a 10% plus to max value.
For the 2nd point, i guess you can figure this out with minor/major axis interlaced and offset properties.
First, you'll need to decide on a range for (top of graph)/(max data point). You have this bounded on the lower end as 1.05; reasonable upper bounds might be 1.1 or 1.15. The wider the range, the more empty space may appear at the top of the graph, but the "nicer" the numbers may be. Alternatively, you can pick a "niceness" criterion first and then pick the smallest sufficiently nice number where the above ratio is at least 1.05.
You can also improve the "niceness" of the intervals by loosening that lower bound, for instance lowering it to 1.02 or even 1.0.
EDIT: In response to comment.
What you'll have to do to find a good max size is take your max value plus margin, divide it by the number of intervals, round it upward to the nearest "nice" value, and multiply by the number of intervals. A reasonable definition of "nice" might be "multiple of 10^(floor(log_10(max value)) - 2)" A looser definition of niceness will give you (on average) less extra margin at the top.

Categories

Resources