[interfacekit] Re: programming problems

On 2004-02-02 at 16:17:00 [+0100], Adi Oanca wrote:
> Ingo Weinhold wrote:
> 
> > That's not surprising, given how the constants are constructed. Apparently
> > it is possible to individually specify for each side whether it shall
> > follow the top, left, bottom, right, center (or nothing) of the parent
> > view.
>    Apparently, this is written in BeBook, so we already know that!

You must have a different edition of the BeBook, since both the plain R5 
BeBook as well as annotated one only explain the B_FOLLOW_* constants, not 
how they are constructed.

> > Anyway you can decompose the resizing mode like that:
> > 
> >     uint32 mode = ResizingMode();
> >     uint32 topMode = (mode >> 12) & 0xf;
> >     uint32 leftMode = (mode >> 8) & 0xf;
> >     uint32 bottomMode = (mode >> 4) & 0xf;
> >     uint32 rightMode = mode & 0xf;
> > 
> > And then analyze the value for each side:
> > 
> >     // top side follows...
> >     switch (topMode) {
> >         case 0:
> >             // ... nothing
> >             break;
> >         case _VIEW_TOP_:
> >             // ... parent's top
> >             break;
> >         case _VIEW_LEFT_:
> >             // ... parent's left? -- meaning?
> >             break;
> >         case _VIEW_BOTTOM_:
> >             // ... parent's bottom
> >             break;
> >         case _VIEW_RIGHT_:
> >             // ... parent's right? -- meaning?
> >             break;
> >         case _VIEW_CENTER_:
> >             // ... parent's vertical center
> >             break;
> >     }
>    Did you read the hole email I previously sent?

I did.

>    I said:
> "and I've come upon a problem at witch I want an easy answer, answer
> that I failed to find so far."
> 
>    Easy Ingo, easy! I'm not going to write all those structures for a
> simple point.Set(x,y)!

If you re-read your original mail yourself, you will find (at least I do) 
that it sounds like you have no solution at all, since the only thing you 
mention is something which doesn't work and is far enough off track to 
suggest that.

Really, this game starts to annoy me. I reply to mails, when I feel, that my 
answer can be of some help, and I'm glad, if it indeed is. But when the 
reaction is to question of my ability to read a six line mail carefully 
enough to grasp its meaning, then I really wonder why to waste my time in the 
first place.

> Anyway, I had a solution but I was not fond of it. In the mean time it
> appears I've found one:
> 
>         // resize/move horizontaly
>     if ((rmask & 0x00000f00UL)>>8 == _VIEW_LEFT_
>             && (rmask & 0x0000000fUL)>>0 == _VIEW_RIGHT_){
>         printf("1\n");
>     }
>     else if ((rmask & 0x00000f00UL)>>8 == _VIEW_LEFT_){
>         printf("2\n");
>     }
>     else if ((rmask & 0x0000000fUL)>>0 == _VIEW_RIGHT_){
>         printf("3\n");
>     }
>     else if ((rmask & 0x00000f00UL)>>8 == _VIEW_CENTER_){
>         printf("4\n");
>     }
>     else { // illegal flag. Do nothing.
>         printf("5\n");
>     }

This case distinction is incomplete, as you, for instance, don't catch cases 
like 
  _rule_(0, _VIEW_LEFT_, 0, _VIEW_CENTER_)
or
  _rule_(0, _VIEW_CENTER_, 0, _VIEW_RIGHT_).

Not to mention unusual settings like 
  _rule_(0, 0, 0, _VIEW_LEFT_)
or
  _rule_(0, _VIEW_RIGHT_, 0, 0).

Or perhaps meaningless (but still to be proven so) things like
  _rule_(0, _VIEW_TOP_, 0, 0).

>         // resize/move verticaly
>     if ((rmask & 0x0000f000UL)>>12 == _VIEW_TOP_
>             && (rmask & 0x000000f0UL)>>4 == _VIEW_BOTTOM_){
>         printf("1\n");
>     }
>     else if ((rmask & 0x0000f000UL)>>12 == _VIEW_TOP_){
>         printf("2\n");
>     }
>     else if ((rmask & 0x000000f0UL)>>4 == _VIEW_BOTTOM_){
>         printf("3\n");
>     }
>     else if ((rmask & 0x0000f000UL)>>12 == _VIEW_CENTER_){
>         printf("4\n");
>     }
>     else { // illegal flag. Do nothing.
>         printf("5\n");
>     }

Ditto.

>    I did tried to use B_FOLLOW_* flags but they lead to a very ugly
> looking code. So I adopted those 5 undocumented flags with the help of
> which the code seems more readable, but still not easy!
> 
> NOW, I have an idea!
> ...
> And this what it came out:
> 
> Ingo Weinhold wrote:
>  > On 2004-02-01 at 23:06:23 [+0100], Andrew Bachmann wrote:
>  >>Assuming that the constants are multi-bit, I think the most reliable
> way to
>  >>test would be to use a
>  >>construct like this:
>  >>
>  >>if (ResizingMode() & B_FOLLOW_LEFT_RIGHT == B_FOLLOW_LEFT_RIGHT)
>  >>....
>  >>if (ResizingMode() & B_FOLLOW_LEFT == B_FOLLOW_LEFT)
>  >>....
>  >>if (ResizingMode() & B_FOLLOW_RIGHT == B_FOLLOW_RIGHT)
>  >>....
>  >
>  >
>  > This won't work in general, since it holds for instance:
>  >     B_FOLLOW_BOTTOM & B_FOLLOW_TOP == B_FOLLOW_TOP
>    But will work if placed in the proper order!
>    Had tried that before, but it is only now I got inspired. :-)
> 
> And, that order is:
>         // resize/move horizontaly
>     if ((rmask & B_FOLLOW_H_CENTER) == B_FOLLOW_H_CENTER){
>         printf("1\n");
>     }
>     else if ((rmask & B_FOLLOW_LEFT_RIGHT) == B_FOLLOW_LEFT_RIGHT){
>         printf("2\n");
>     }
>     else if ((rmask & B_FOLLOW_RIGHT) == B_FOLLOW_RIGHT){
>         printf("3\n");
>     }
>     else if ((rmask & B_FOLLOW_LEFT) == B_FOLLOW_LEFT){
>         printf("4\n");
>     }
>     else { // illegal flag. Do nothing.
>         printf("5\n");
>     }
> 
>         // resize/move verticaly
>     if ((rmask & B_FOLLOW_V_CENTER) == B_FOLLOW_V_CENTER){
>         printf("1\n");
>     }
>     else if ((rmask & B_FOLLOW_BOTTOM) == B_FOLLOW_BOTTOM){
>         printf("2\n");
>     }
>     else if ((rmask & B_FOLLOW_TOP_BOTTOM) == B_FOLLOW_TOP_BOTTOM){
>         printf("3\n");
>     }
>     else if ((rmask & B_FOLLOW_TOP) == B_FOLLOW_TOP){
>         printf("4\n");
>     }
>     else { // illegal flag. Do nothing.
>         printf("5\n");
>     }

Ouch! Sorry, but what you're doing is fighting the structure. The resizing 
mode is a four component field and &-ing multiple components at once with 
constants that are not intended for this purpose simply isn't a clean 
solution. Don't misunderstand me, it may work, but I wouldn't even care to 
check if it does.

OK, let me guess, what the actual problem is, that shall be solved (at least 
it's the only thing I imagine why one would want to analyze the resizing 
mode): The frame of a parent view has changed and the task is to compute the 
new frame of a child view according to its resizing mode.

Given:

BRect oldParentFrame, newParentFrame;
BRect oldChildFrame;
uint32 resizingMode;

To be computed:

BRect newChildFrame;

Algorithm:

// decompose the mode
uint32 topMode = (resizingMode >> 12) & 0xf;
uint32 leftMode = (resizingMode >> 8) & 0xf;
uint32 bottomMode = (resizingMode >> 4) & 0xf;
uint32 rightMode = resizingMode & 0xf;

// compute centers
float oldHCenter = floor((oldParentFrame.left + oldParentFrame.right) / 2);
float newHCenter = floor((newParentFrame.left + newParentFrame.right) / 2);
float oldVCenter = floor((oldParentFrame.top + oldParentFrame.bottom) / 2);
float newVCenter = floor((newParentFrame.top + newParentFrame.bottom) / 2);

// compute parent frame deltas
float dl = newParentFrame.left - oldParentFrame.left;
float dt = newParentFrame.top - oldParentFrame.top;
float dr = newParentFrame.right - oldParentFrame.right;
float db = newParentFrame.bottom - oldParentFrame.bottom;
float dhc = newHCenter - oldHCenter;
float dhv = newVCenter - oldVCenter;

// compute the new child frame
newChildFrame = oldChildFrame;
newChildFrame.left += resize_delta(leftMode, dl, dt, dr, db, dhc);
newChildFrame.top += resize_delta(topMode, dl, dt, dr, db, dvc);
newChildFrame.right += resize_delta(rightMode, dl, dt, dr, db, dhc);
newChildFrame.bottom += resize_delta(bottomMode, dl, dt, dr, db, dvc);

Helper function:

float
resize_delta(uint32 mode, float dl, float dt, float dr, float db, float dc)
{
        switch (topMode) {
                case _VIEW_TOP_:                return dt;
                case _VIEW_LEFT_:       return dl;
                case _VIEW_BOTTOM_:     return db;
                case _VIEW_RIGHT_:      return dr;
                case _VIEW_CENTER_:     return dc;
                case 0: default:                return 0;
        }
}

If weird combinations like _VIEW_TOP_ or _VIEW_BOTTOM_ for the left side 
shall be ignored (that remains to be checked), they can either be filtered 
out in the constructor respectively SetResizingMode() and/or one can do it 
like that:

newChildFrame.left += resize_delta(leftMode, dl, 0, dr, 0, dhc);

> I think we shall make this public. Others may have the same problem.

Mmh, I can't imagine who could possibly be interested in analyzing a resizing 
mode. I mean, the API user sets it at view construction or later via 
SetResizingMode(), but why should one care to check it later on?

CU, Ingo

Other related posts: