0
\$\begingroup\$

So I am building custom UI for my MonoGame project. I've gotten pretty far already, having created Controls such as:

  • Button
  • Panel
  • TextBox
  • Form
  • ComboBox
  • CheckBox
  • etc.

All of these controls obviously inherit from my abstract class Control.

This is how I check for Click on a Control:

if (Destination.Intersects(inputManager.MouseRect) && inputManager.IsMouseClicked(MouseButton.Left)) {
    Click?.Invoke(this, EventArgs.Empty);
    _focused = true;
}
else if (!Destination.Intersects(inputManager.MouseRect) && inputManager.IsMouseClicked(MouseButton.Left)) {
    _focused = false;
}

This method has gotten me pretty far already, but unfortunately it doesn't work when there are multiple TextBoxes: each TextBox I click on will become focused, and any key I press will be typed in every focused TextBox.

Here is how I hacked around this:

  • Since all Controls (including TextBoxes) the user sees are placed in a certain Panel, they are in that panel's array of Controls.
  • I added a Panel _parent to the Control class, thus every control would have a reference to the panel that owns it
  • Then in the Panel class I added a Control FocusedControl, so that every Panel will have one field for its focused control

So now I'm checking like this:

if (_parent.FocusedControl == this)
    // This specific control is focused

Or like this:

if (_parent.FocusedControl != null)
    // There is a focused Control

if (_parent.FocusedControl == null)
    // No control is focused in this panel

This works.

But the problem is that I am doing these checks in the controls themselves, and not, for example, in the Panel class.

This means each control has a reference to the panel that owns it, and that panel has a list of all the controls. Also the panel's public methods and properties are available to the owned control.

This eliminates encapsulation and is effectively terrible design.

I consider this to be a huge mess and a dirty hack. Is there any other way to make sure that a Panel has only one focused Control at a time?

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

This is not a perfect method but you can try if it is better than yours.

First, you don't need to check both Intersects and Click event in one line of code. Just check intersect first, if the condition is true then check Click, if it is false, we don't need to check the second condition.

Create a list of GUI control:

public List<GUI_Control> controls = null;
public bool focus=false;
public GUI_Control parent=null; 

Then check the mouse event:

public override bool MouseDownEventLeft(float mouse_x, float mouse_y) {
 if (!visible) return false;
 //if intersects
 if (inside(mouse_x, mouse_y)) {
  if (controls != null && controls.Count > 0) {
   // hand to my children controls
   for (int i = 0; i < controls.Count; i++) {
    bool rc = controls[i].MouseDownEventLeft(mouse_x, mouse_y);
    if (rc) return true;
   }
  }
  parent.clearFocus(true);//clear focus on parent GUI
  focus = true;
  return true;
 }
 return false;
}

Then each time you click, only one textbox (or something else) is being focused (its focused boolean is true).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .