0

This function will loop through rectangles painted in normal order(I'm implementing the painter's algorithm). However, I made the event handling loop into reversed order so the last rectangle drawn will be the priority of event handling. If one of the rectangles has been hovered by mouse, break the loop then reset the other rectangle.hovering attribute to false except the current rectangle being hovered. I have seen the repetition of code here so I would like to transform it into recursive one to make it flexible. Here I present the awful, limited and not flexible code yet functioning.

void swcApplication::overrideOnMouseMove(int x, int y)
{
    static swcWidget *prev_widget = nullptr;

    auto i = controls.getWidgets().size();

    while (i)
    {

        auto &widget = controls.getWidgets()[--i];

        if (!widget->enable) continue;

        auto j = widget->components.size();

        while (j)
        {

            auto &widget_component1 = widget->components[--j];

            if (!widget_component1->enable) continue;

            auto k = widget_component1->components.size();

            while (k)
            {

                auto &widget_component2 = widget_component1->components[--k];

                if (!widget_component2->enable) continue;

                widget_component2->hovering = widget_component2->contains(x, y);

                widget_component2->efOnMouseMove(x, y);

                if (widget_component2->hovering)
                {

                    if (prev_widget != nullptr &&
                        prev_widget != widget_component2)
                    {
                        prev_widget->hovering = false;

                        prev_widget->efOnMouseMove(x, y);
                    }

                    prev_widget = widget_component2;

                    widget_component1->hovering = false;

                    break;
                }
            }

            widget_component1->hovering = widget_component1->contains(x, y);

            widget_component1->efOnMouseMove(x, y);

            if (widget_component1->hovering)
            {

                if (prev_widget != nullptr &&
                    prev_widget != widget_component1)
                {
                    prev_widget->hovering = false;

                    prev_widget->efOnMouseMove(x, y);
                }

                prev_widget = widget_component1;

                widget->hovering = false;

                break;
            }
        }

        widget->hovering = widget->contains(x, y);

        widget->efOnMouseMove(x, y);

        if (widget->hovering)
        {
            if (prev_widget != nullptr &&
                prev_widget != widget)
            {
                prev_widget->hovering = false;

                prev_widget->efOnMouseMove(x, y);
            }

            prev_widget = widget;

            break;
        }
    }
}

I attempted to make my own recursive function to do this but it only works if I started hovering from the very last rectangle painted. If I started to hovering from the very first rectangle painted, it became buggy and I cannot figure out what order(of event) and condition I should make to imitate the iterative one.

Here is the code for recursive function call

//post-order traversal
void swcApplication::recursiveOnMouseMove(swcWidget *next, int x, int y)
{
    if (!next->enable) return;

    static swcWidget *prev_widget = nullptr;

    auto i = next->components.size();

    while (i)
    {
        auto &next_component = next->components[--i];

        recursiveOnMouseMove(next_component, x, y);
    }


    if (prev_widget != nullptr &&
        prev_widget != next &&
        prev_widget->hovering)
    {
        prev_widget->hovering = false;

        prev_widget->efOnMouseMove(x, y);

        prev_widget = next;

        return;
    }

    next->hovering = next->contains(x, y);

    next->efOnMouseMove(x, y);

    prev_widget = next;
}


//Here is the big loop
//prioritize first all rectangle.components w/c are another rectangle also (...so on and so forth)
while (i)
{
    auto &widget = controls.getWidgets()[--i];

    recursiveOnMouseMove(widget, x, y);
}

BTW: I am making a GUI simulated through OpenGL

mr5
  • 3,438
  • 3
  • 40
  • 57
  • About `static swcWidget *prev_widget1 = nullptr;` and other similar lines with `static`, the use of `static` may be unnecessary, and may even cause problems when calling the method on multiple threads. – Mark Garcia Feb 17 '14 at 04:47
  • @MarkGarcia I used it to keep a track from the previous `rectangle` being drawn and I don't know any other solution to keep a track from the other. (Hey there, remember me? haha) – mr5 Feb 17 '14 at 04:49
  • I just want to say that if you could make them class members then it is better to have them as such, which has the advantage of being easily identified as such, versus `static`s being hidden beneath other code. Making them class members also makes more sense as it conveys the state of the object, and not of the function. (*And yeah, I remember you `:)`*) – Mark Garcia Feb 17 '14 at 04:54
  • @MarkGarcia I'm trying to separte the `widgets` w/c are the rectangles from `app` w/c handles all the logic on how each widgets will interact w/ each other. `swcWidgets` alone hasn't any logic at all and will not respond to any event, and according to my idea, this should be manipulated by the controller w/c happens to be the `swcApp`. *(I already solved my border arcs problem :D, did you see [it](http://stackoverflow.com/questions/19968624/imitating-htmls-flexible-rectangle) and also the final [implementation](http://stackoverflow.com/questions/20508259/draw-a-curved-line-from-an-arc-edge))`* – mr5 Feb 17 '14 at 05:07

1 Answers1

0

After hours of trial and error, I just figure out my question again! HAHA

This is just the right solution what I am looking for:

What I did is I made a global *ptr and set it to nullptr

swcWidget *prev = nullptr;

Then I traversed it in post-order like this

void swcApplication::recursiveOnMouseMove(swcWidget *next, int x, int y)
{
    if (!next->enable) return;

    //self explanatory
    if (prev != nullptr && prev != next)
    {
        next->hovering = false;

        //perform visitation and tell them a bad news
        next->efOnMouseMove(x, y);

        return;
    }

    auto i = next->components.size();

    while (i)
    {
        auto &next_component = next->components[--i];

        recursiveOnMouseMove(next_component, x, y);
    }

    next->hovering = next->contains(x, y);

    //perform visitation
    next->efOnMouseMove(x, y);

    //Then I made a track for the very first rectangle to be hovered!
    if (next->hovering)
        prev_widget = next;
}

Then on outermost loop

What I did is this

void swcApplication::overrideOnMouseMove(int x, int y)
{

    auto i = controls.getWidgets().size();

    //for every widget, do postorder traversal
    while (i)
    {
        auto &widget = controls.getWidgets()[--i];

        recursiveOnMouseMove(widget, x, y);
    }

    //re-assign it to `nullptr`
    prev = nullptr;
}

Hope someone could help by this :D

mr5
  • 3,438
  • 3
  • 40
  • 57