setVisible protected

Jekteir

20-05-2010 22:23:00

Hiya, -- hello again :)

I've got a bit of time to work on my project, so I got the latest QuickGUI (nice work, by the way) and Ogre and things are going swimmingly.

However, I've just added a function to allow me to set a widget visible using its name:

void GUIBoss::setWidgetVisible(Ogre::String &widgetName, bool visible)
{
QuickGUI::Widget *w = (QuickGUI::Widget*)guiMgr->getActiveSheet()->findWidget(widgetName);
w->setVisible(visible);
}

On compile I get:

error C2248: 'QuickGUI::Widget::setVisible' : cannot access protected member declared in class 'QuickGUI::Widget'
Is there a way for me to change a Widget's visibility without first casting it to the correct type of widget for what it actually is? If there isn't, is there a function which will allow me to quickly get the right type of any widget and then cast a Widget* to a pointer of that type?

Is there a reason why setVisible is protected? Surely all widgets can be visible/invisible, so is there a reason to force an implementation further down the inheritance tree?

Many thanks,

Jek

Jekteir

20-05-2010 22:49:03

I'm also having problems with this:

guiMgr->getMouseCursor()->setVisible(true);
guiMgr is a QuickGUI::GuiManager*.

I get:

error C2248: 'QuickGUI::GUIManager::getMouseCursor' : cannot access protected member declared in class 'QuickGUI::GUIManager'



***EDITED: Note: I have gotten this part of the functionality working with:

guiMgr->getActiveSheet()->setMouseCursorVisible(visible);

kungfoomasta

20-05-2010 23:45:04

Every widget should have a "getClassName" API or similar, which should return "Button", "Window", etc.

The idea was that certain Widgets like Menu Items shouldn't be controlled by users, however my current thought it that I could have left it as public, and allowed users to make weird GUIs if they wanted to.

I'm currently making a new version of QuickGUI, and its a pretty dramatic change. API access is one of the things I'm thinking about, but in general I will try not to force things so much, allowing users to do things that wouldn't normally make sense. (In your function you could pass in a toolbar item, menuitem, or listitem, and things would look kind of funky. :lol: )

Jekteir

20-05-2010 23:50:38

I wish you wouldn't make 'dramatic changes'... It seems like every version is a 'dramatic change'. Ongoing support and development of existing stuff would be perfect :P

Yeah, I could get the class name, but then if I wanted to be able to set any widget visible/invisible (which I do), or change the text on any widget that can handle text (which I do), I'd have to do a whole list of if statements, cast the widget accordingly and then call the specific function on the new pointer.

Jekteir

20-05-2010 23:52:31

Would you be able to give me a hint on some slightly tricky code?

I've implemented a console that pops up when you hit Enter and disappears when you hit Enter again. But I want to be able to make the console disappear when you hit Enter _only_ if the input textbox of the console was empty at the moment you hit enter. If it had text, I want it to submit the text but not change the visibility.

What's the best way to interrogate the text within the input box, if I know when Enter has just been pressed?

Thanks,

Jek

kungfoomasta

21-05-2010 18:08:27

I'm basically re-writing the lib from scratch. :P The new benefits will be too great to ignore. 8)

For your console question, I would probably make use of:

- Console::setConsoleInputHandler

Add an input handler, the signature requires the following parameters:
void myInputHandler(Console* console, bool& clearInputBox, bool& addToDisplayArea)

If you want to know if the InputBox text is empty, call Console::getInputBoxText, and call empty().

Quick and Dirty:
void myClass::myInputHandler(Console* console, bool& clearInputBox, bool& addToDisplayArea)
{
if(console->getInputBoxText().empty())
console->setVisible(false);
else
{
clearInputBox = true;
addToDisplayArea = true;
// do something now that a command has been entered, this is app specific
}
}

Jekteir

21-05-2010 21:48:37

Thanks very much for the info -- that looks exactly like the sort of thing I need. I'll try linking that up to the network etc soon.

At least if you end up doing some crazy rewrites on the lib, try and generally keep the function calls etc the same, please! :) It was nice to update the library without too much hassle this time, and I hope it will continue to become increasingly backward-compatible in terms of interfaces (perhaps just with fewer protected functions, wink wink).

kungfoomasta

21-05-2010 23:43:17

I'm currently leaning towards having a base Widget class that will support a lot of getX functions, and then having other classes like EditableWidget, which supports certain setX functions. So for your original scenario, you would try to dynamic cast the widget to an EditableWidget, and if the pointer was non-NULL, you could then call the setVisible function. If the pointer became NULL, it means you passed in a non-editable widget, like a MenuItem.

Jekteir

22-05-2010 03:01:38

That sounds good.

Here's a thought, though -- would you need another class called CanBeVisible or something, so we get can getVisible() and setVisible()?

If in your current thinking you would, I suggest that maybe the things that shouldn't be 'set' or gotten visibility on, might not actually be widgets. Maybe they should be WidgetComponents, and as such, separate from the various widget functions altogether, freeing up the base Widget class for getVisible, setVisible etc.

But the Editable stuff sounds good.

Also, just in terms of tips -- is there a way to pass strings in for setting text etc without first casting to Ogre::String? It would be nice to send a C-style normal character array, and I think sometimes when I try that, it fails.

kungfoomasta

22-05-2010 20:34:48

Instead of casting why not create an Ogre string from a c-style string, and use that? :P

Next version will have Rendering abstracted, I won't be tieing into Ogre classes at all. (That means no Ogre::String, among a ton of other classes)

Of course, I'll also provide my classes that bridge QuickGUI and Ogre together, similar to how the Ogre team provided the OgreCEGUIRenderer and OgreCEGUITexture classes. (although I have a different set of classes.. still figuring it out)

Jekteir

24-05-2010 01:40:04

Heya,

I'm going great guns with the networking stuff. I can successfully send a test chat message.

Now I'd like to link that message-sending to the QuickGUI console. I tried:

cslChat->addWidgetEventHandler(QuickGUI::WIDGET_EVENT_KEY_UP,&Game::consoleKeyUp,(Game*)caller);
But that event handler was never called when a key was pressed in the console. Can you tell me if I should be adding some other sort of event, or an event on a component part of this console, in order to intercept a key-up event? I want to check if the event is a KC_RETURN key, and if it is, send the current contents of the input text box over the network.

Cheers!

Jek

Jekteir

24-05-2010 02:23:13

Update:

I found this function:
cslChat->addCharEnteredEventHandler(&Game::consoleKeyUp,(Game*)caller);
Now my function gets called when a character gets entered.

This is the way I want to use that information:

void Game::consoleKeyUp(const QuickGUI::EventArgs& args)
{
const QuickGUI::KeyEventArgs &mea = dynamic_cast<const QuickGUI::KeyEventArgs&>(args);

if (mea.scancode == QuickGUI::KC_RETURN)
{
netMgr->sendChatMsg(dynamic_cast<QuickGUI::Console*>(mea.widget)->getInputBoxText());
}
}

However, right now I'm finding that the scancode is actually only equal to the key that fired _before_ the key you just pressed. And I have no idea why this is. E.g. if I were waiting for KC_S, and I typed a s d, it's only when I type 'd' that the if (mea.scancode == QuickGUI::KC_S) would actually return true.

I don't know why this is.

Moreover, I'm now getting a crash in quickguiconsole.cpp at:
Ogre::UTFString Console::getInputBoxText()
{
return mInputBox->getText();
}

Unhandled exception, access violation reading location. That happens as I'm trying to getInputBoxText().


Any idea what could be up here?

Many thanks,

Jek

kungfoomasta

24-05-2010 17:43:20

In the TextBox code, I see this:

addWidgetEventHandler(WIDGET_EVENT_CHARACTER_KEY,&TextBox::onCharEntered,this);

This basically means that if you press 's', and you see an 's' displayed, the event was fired. Not sure why your values seem incorrect, you'd have to set a breakpoint in

bool GUIManager::injectChar(Ogre::UTFString::unicode_char c)

And see how pressing 'd' will report an 's'.

The access violation issue is odd, is mInputBox somehow NULL? If the console has been created (and automatically initialized) I don't see how this could happen. Have to debug it, or provide repro code. (easiest if you can debug :) )

Jekteir

24-05-2010 18:36:17

Heavens curse me, but I'm using a DLL build. But I'll see what I can do.

But it isn't that 'when you press a 'd' you get an 's''. It's that the character code is always the one for the character _before_ the one you just entered, whichever they might be in the example. E.g. if you pressed 'q' 'w' 'e' 'r' then when you hit the w the event would have q, when you hit e it would say w, etc etc.

*edited to change 'it is that' to 'it ISN'T that'.