Scaleable GUI Box/Labels - c#

My GUI Boxes and Labels are set by Coordinates. How would I set them to scale with resolution and screen size as they go off screen on build. The first IF statement the GUI displayed on the top left of screen and then next displays on the top right! Code examples would be very helpful!
public void OnGUI()
{
if ((isClicked) && (cdrwModel))
{
GUI.contentColor = Color.white;
GUI.Label(new Rect(5, 5, 400, 400), "<color=cyan><size=30>This is the </size></color>" + "<color=cyan><size=30>" + this.cdrw + "</size></color>");
GUI.Label(new Rect(15, 35, 400, 400), "Press <TAB> for more information");
if (showGui)
{
GUI.contentColor = Color.white;
GUI.Box(new Rect(1000, 5, 400, 400), "What You Should Know");
GUI.Label(new Rect(1135, 5, 400, 400), "___________________");
GUI.Label(new Rect(1145, 23, 400, 400), "<color=cyan><size=20>The </size></color>" + "<color=cyan><size=20>" + this.cdrw + "</size></color>");
foreach (var file in _puzzlesFile)
{
GUI.contentColor = Color.white;
GUI.Label(new Rect(1000, 50, 400, 400), file);
}
}
}
}

You can use Screen class to get current Screen.width and Screen.height and create something to recalculate your GUI coordinates when it changes. If your game camera doesn't uses entire screen you can get Camera.current.pixelWidth/pixelHeight to do the same.
If you want a responsive UI you should avoid coordinates and use GUILayout instead of GUI class to declare your components, it is way better and easier to adjust without a lot of handmade calculations that can (and probably will) blow your performance out.

Just use Screen.width for width and x position of GUI and Screen.height for height and y position of GUI.
For Example:, for a screen resoulution for 1024:640
GUI.Box(new Rect(Screen.width/10, Screen.height/10, Screen.width/3, Screen.height/5), "What You Should Know");
will create a Gui box same with
GUI.Box(new Rect(102.4f, 64, 341.3f, 128), "What You Should Know");
but first one will be responsive.

Related

Unity IMGUI override GL calls

I am trying to develop a little tool for the Unity editor using IMGUI and GL, and I came up with a problem.
I have the following code:
public class TestWindow : EditorWindow
{
[MenuItem("TEST/Test")]
static void Open()
{
var window = GetWindow<Test>();
window.Show();
}
void OnGUI()
{
DrawSquare(new Rect(10, 10, 20, 20), Color.red);
DrawSquare(new Rect(10, 40, 20, 20), Color.magenta);
GUIStyle style = new GUIStyle("label");
style.normal.background = Texture2D.whiteTexture;
style.normal.textColor = Color.black;
style.alignment = TextAnchor.MiddleCenter;
GUI.Label(new Rect(40, 10, 80, 50), "Hello World", style);
DrawSquare(new Rect(130, 10, 20, 20), Color.blue);
DrawSquare(new Rect(130, 40, 20, 20), Color.cyan);
}
private static void DrawSquare(Rect rect, Color color)
{
GL.PushMatrix();
GL.Begin(GL.QUADS);
GL.Color(color);
GL.Vertex3(rect.xMin, rect.yMin, 0);
GL.Vertex3(rect.xMax, rect.yMin, 0);
GL.Vertex3(rect.xMax, rect.yMax, 0);
GL.Vertex3(rect.xMin, rect.yMax, 0);
GL.End();
GL.PopMatrix();
}
}
The problem that I am having is that it seems like GUI.Label is blocking the remaining GL calls from being drawn in the editor window. If you run this code, you will see the red and magenta squares, followed by the label, but the blue and cyan squares are not drawn. If you comment/remove the label, then they are. I tried without the style as well and made no difference.
I managed to find out that any GUI call that will draw content into the window will block the other two squares from being drawn. For example, drawing a GUI.Label with empty string text, will still draw the blue and cyan squares.
I saw the C# reference source code from Unity, and I notice that there is a check for empty string before calling some native code, so I assume that the issue comes all the way from C++.
If anyone knows how could I prevent this (maybe there is some GL or C# method that I can use to prevent this) I would appreciate it.
P.S: Worst case scenario I can handle the code to draw all GL stuff first, and then any GUI calls, but I still would like to be able to mix them freely if there is a way.

DrawArc works correct for circle but invalid for ellipse

I am drawing using System.Drawing.Graphics class.
I need my application to draw arcs for both circles and ellipses.
Here is a code example
graphics.DrawArc(Pens.Black, new Rectangle(100, 100, 100, 100), 135, 270);
graphics.DrawArc(Pens.Black, new Rectangle(100, 210, 100, 75), 135, 270);
graphics.DrawArc(Pens.Black, new Rectangle(100, 290, 100, 50), 135, 270);
graphics.DrawArc(Pens.Black, new Rectangle(100, 350, 100, 25), 135, 270);
Image below shows the result.
I just cannot understand why the gap between the two points is reducing? I expect it to remain the same?
Look here - all right angles:
You may get a better idea of what's happening if you consider the limit case of vanishing height.

Graphics bug when dragged off-screen

I have wrote this code that will create a rounded corner border around a panel.
public void DrawRoundRect(Graphics g, Pen p, float X, float Y, float width, float height, float radius)
{
GraphicsPath gp = new GraphicsPath();
//Upper-right arc:
gp.AddArc(X + width - (radius * 2), Y, radius * 2, radius * 2, 270, 90);
//Lower-right arc:
gp.AddArc(X + width - (radius * 2), Y + height - (radius * 2), radius * 2, radius * 2, 0, 90);
//Lower-left arc:
gp.AddArc(X, Y + height - (radius * 2), radius * 2, radius * 2, 90, 90);
//Upper-left arc:
gp.AddArc(X, Y, radius * 2, radius * 2, 180, 90);
gp.CloseFigure();
g.DrawPath(p, gp);
gp.Dispose();
}
private void panel_Paint(object sender, PaintEventArgs e)
{
Graphics v = e.Graphics;
DrawRoundRect(v, Pens.White, e.ClipRectangle.Left, e.ClipRectangle.Top, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1, 10);
base.OnPaint(e);
}
It works fine, until it goes off screen and this happens:
Does anyone know what I've done wrong, or how to fix the issue?
You misunderstand what ClipRectangle means.
It doesn't tell you how big the panel is - it tells you which part of the panel to redraw. As you move the form off-screen, it needs to redraw the parts that changed monitors - but not the ones that remain on the original one. So instead of redrawing the whole panel (when ClipRectangle is the whole area of the panel, and your code works), it tells you to only redraw a part of it - and ClipRectangle is much smaller than the panel you're trying to draw.
ClipRectangle is really an optimization feature. If you don't care about that, you can pretty much ignore it completely - just use 0, 0, panel.Width, panel.Height.
You have two problems. First is relying on e.ClipRectangle, that is not the size of the panel. You need to use panel.ClientRectangle instead. That's what causes the smearing when you drag it off the screen and back.
You haven't found the next one yet, it is much more subtle. Panel was designed to be a container control and it optimizes its painting. Redrawing only the parts that get revealed when it is resized. Pretty important, makes resizing a window more bearable. That however will not work well for details like this, the rounded corners will not get properly repainted. Looks like a smearing effect as well, less pronounced than what you have now. It will happen whenever you resize the panel, typically with the Dock or Anchor property.
Proper way to do that is to derive your own class from Panel, set the ResizeRedraw property to true in the constructor. You typically almost always also want to set DoubleBuffered to true to suppress the visible flicker you now have. Or use the panel's Resize event, call panel.Invalidate().

Changing font size of button

Okay this may be really simple, but every attempt I make the console throws up various errors. If i have if(GUI.Button(new Rect(x, y, Screen.width, z), "play")) { How would I go about changing the size of the text. I have a custom GuiSkin used on the text, but I'm unsure how to change the font size of the text without using the inspector - I am using unity. What I am trying to do is change the font size depending on the screen resolution.
If you have create your GUiSkin object, first you can using inspector to change GuiSkin.Button.FontSize. Then apply this setting in you button.
public GUISkin yourGuiSkinObject;
void OnGUI()
{
if(GUI.Button(new Rect(0, 0, 100, 20), "Test", yourGuiSkinObject.button))
{
//Do something.
}
}
Second you can using script to change fontSize. And change the size depend on the screen's height.
public GUISkin yourGuiSkinObject;
void Start()
{
int scale = Screen.height / 20;
yourGuiSkinObject.button.fontsize = scale;
}
void OnGui()
{
if(GUI.Button(new Rect(0, 0, 100, 20), "Test", yourGuiSkinObject.button))
{
}
}

Simple graphic problem

I have never really had to worry about how "pretty" my programs are before but I'm working on something for marketing now.... Anyways I imagine this is pretty simple but I can't seem to figure out why this isn't working. Basically I have a panel with a bunch of picture boxes in it and I am drawing colored rectangles behind them to create a pseudo "frame" around the photos. It has a different frame based on whether or not the photo is selected. The default selected photo is in position 0 and on the first time it paints everything looks great. But when the selection is changed, the paint event fires and nothing changes. Here's the code:
private void panelPicSet_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(panelPicSet.BackColor);
foreach (PictureBox picBox in panelPicSet.Controls)
{
if (picBox == selectedPhoto.PictureBox)
g.FillRectangle(new SolidBrush(Color.FromArgb(53, 73, 106)), new Rectangle(new Point(picBox.Location.X - 4, picBox.Location.Y - 4), new Size(picBox.Width + 8, picBox.Height + 8)));
if (picBox == hoveredPicBox)
g.FillRectangle(new SolidBrush(Color.FromArgb(53, 73, 106)), new Rectangle(new Point(picBox.Location.X - 2, picBox.Location.Y - 2), new Size(picBox.Width + 4, picBox.Height + 4)));
else
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 232, 166)), new Rectangle(new Point(picBox.Location.X - 2, picBox.Location.Y - 2), new Size(picBox.Width + 4, picBox.Height + 4)));
}
}
Like I suspected it was an easy answer. I had to call panelPicSet.Invalidate() in the click and mouse enter/ leave events. I had assumed that clearing the graphics object in the paint event was performing the same function but apparently not.

Categories