.NET/WinForms Custom Form Border with Minimize Animation - c++

I know I've seen this asked before, but the answers have been inconclusive or unsatisfactory (from what I could see), so I'd like to pose my situation here. I'm creating a program that has a custom form border (i.e. Form Border Style = None with our own controls around it). The program doesn't have the minimize/close animations, but just snaps, instead.
It is a .NET form (using C++/CLR) - is there something I can do? I've seen other programs do this (for example, Photoshop CS6/CC have the restore animation, but not the minimize one).
Is there a property/style I can apply by overriding the CreateParams? I'm game for "hacky" methods, but changing the form border style in a way that lets the user temporarily see the border isn't a viable option here.
Thanks in advance.

I ended up using a custom animation and figured I would share the relevant code. The following override of the WndProc catches minimizes/restores (including from clicking/double clicking in the taskbar). Be aware, setting the WindowState WILL NOT trigger this - you have to manually send the SC_MINIMIZE lpa with the WM_SYSCOMMAND to the window (or manually animate it). The entire animation code, timer included is below.
//Define a variable so it knows what animation is happening
short fade_mode = 0; //0 is fade in, 1 is minimize, 2 is close
short close_on_close = FALSE; //a variable to tell the close handler to re-animate or not - this allows this->Close(); to trigger the animation but avoids a loop.
//The WndProc
protected: virtual void WndProc(System::Windows::Forms::Message% msg) override {
switch (msg.Msg) {
case WM_SYSCOMMAND:
switch (msg.WParam.ToInt32()) {
case SC_MINIMIZE:
msg.Result = IntPtr::Zero;
fade_mode = 1;
fadetimer->Start();
return;
break;
}
break;
case WM_ACTIVATE: {
if (HIWORD(msg.WParam.ToInt32()) == 0) { //because non-zero wpa here means the form is minimized
this->WindowState = FormWindowState::Normal;
fade_mode = 0;
fadetimer->Start();
msg.Result = IntPtr::Zero;
return;
}
}
}
Form::WndProc(msg);
}
//The button event handlers
private: System::Void btn_close_Click(System::Object^ sender, System::EventArgs^ e) {
this->Close();
}
private: System::Void btn_minimize_Click(System::Object^ sender, System::EventArgs^ e) {
SendMessage(HWND(this->Handle.ToPointer()), WM_SYSCOMMAND, SC_MINIMIZE, NULL);
}
//The event animation code itself (set to a tick of 10ms) and the form closing handler:
private: System::Void fadetimer_Tick(System::Object^ sender, System::EventArgs^ e) {
if (this->IsDisposed == true) { //In the event that the form opened/closed quickly and has not stopped properly, clean up to avoid crashes.
fadetimer->Stop();
return;
}
switch (fade_mode) {
case 0: //fading in
if (this->Opacity < 1)
this->Opacity += 0.2;
else {
fade_mode = -1;
fadetimer->Stop();
}
break;
case 1: //minimizing
if (this->Opacity > 0)
this->Opacity -= 0.2;
else {
fade_mode = -1;
fadetimer->Stop();
this->WindowState = Windows::Forms::FormWindowState::Minimized;
}
break;
case 2: //closing
if (this->Opacity > 0)
this->Opacity -= 0.2;
else {
fade_mode = -1;
fadetimer->Stop();
close_on_close = TRUE;
this->Close();
}
break;
}
}
private: System::Void loginform_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) {
if (close_on_close == FALSE) {
e->Cancel = true;
fade_mode = 2;
fadetimer->Start();
}
}
Be sure to set your form's opacity to 0% by default - it should automatically fade in when it's first created/shown (mine does, I can't remember if I've done something else that makes it so).

Related

Non instantaneous/jerky movement using SDL2 & OpenGL

I've been working on a little 3D engine trying to fix up the camera and make it less jerky. I've been using SDL for the input and while it works it's doing this thing where if I press and hold a button it will instantly move once then pause and then start moving properly making the movement feel unresponsive.
I recorded a GIF of it and while it may be slightly hard to see what's happening hopefully it'll give some idea:
Moving forward and then right would be like:
w wwwwwwwwwwwwwwww a aaaaaaaaaaaaaaaaaaaaa
The important code is here but feel free to ask for more if necessary:
//Poll events
SDL_Event event;
while (m_EngineState != EngineState::EXIT)
{
m_last = m_current;
m_current = SDL_GetPerformanceCounter();
deltaTime = (double)((m_current - m_last) * 1000 / SDL_GetPerformanceFrequency());
while (SDL_PollEvent(&event))
{
switch (event.type) {
case SDL_QUIT:
m_EngineState = EngineState::EXIT;
break;
case SDL_MOUSEMOTION:
break;
case SDL_KEYDOWN:
m_Keys[event.key.keysym.sym] = true;
break;
case SDL_KEYUP:
m_Keys[event.key.keysym.sym] = false;
break;
}
ProcessEvents();
}
void Engine::ProcessEvents()
{
if (m_Keys[SDLK_w])
{
m_Camera->MoveForward(5.0f*(deltaTime*0.001));
}
if (m_Keys[SDLK_s])
{
m_Camera->MoveForward(-5.0f*(deltaTime*0.001));
}
if (m_Keys[SDLK_d])
{
m_Camera->MoveRight(5.0f*(deltaTime*0.001));
}
if (m_Keys[SDLK_a])
{
m_Camera->MoveRight(-5.0f*(deltaTime*0.001));
}
}
void Camera::MoveForward(float amount)
{
m_pos += m_forward * amount;
}
void Camera::MoveRight(float amount)
{
m_pos += glm::cross(m_forward, m_up) * amount;
}
Do not use SDL_PollEvent with the SDL_KEYDOWN and SDL_KEYUP events, it is subject to OS keyboard repeat rates. Which is great for typing, but not for camera/player controls. Use SDL_GetKeyboardState(NULL) in stead to query the current state of the keys.
For example:
Uint8* keystate = SDL_GetKeyboardState(NULL);
if (keystate[SDL_SCANCODE_W])
{
m_Camera->MoveForward(5.0f*(deltaTime*0.001));
}
if (keystate[SDL_SCANCODE_S])
{
m_Camera->MoveForward(-5.0f*(deltaTime*0.001));
}

How to change the state of button to clicked in cocos2d-x

I am pretty new to cocos2d-x.I have created a button and i wanted to change the state of the button when i tap the button . i am having trouble changing the state from play to pause similar to a music player.Below is the code.
void Gallery::buttonUI(Size visibleSize,Vec2 origin)
{
button = Button::create("play.png");
//button->loadTextures("pause.png","play.png","pause.png");
button->setPosition(Point((visibleSize.width/2)+origin.x,(visibleSize.height/2)+origin.y-80));
button->setContentSize(Size(100.0f, button->getVirtualRendererSize().height));
button->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
switch (type)
{
case Widget::TouchEventType::BEGAN:
break;
case Widget::TouchEventType::ENDED:
CCLOG("Characters: %c %c", 'a', 65);
if (!flag)
Gallery::pauseSong();
else
Gallery::resumeSong();
break;
default:
break;
}
});
this->addChild(button);
}
void Gallery::playSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("1.mp3");
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("1.mp3");
flag = false;
}
void Gallery::pauseSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
flag = true;
}
void Gallery::resumeSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
flag = false;
}
I don’t know of such methods for the ui::Button. But I don’t see the use of specific ui::Button items (capinsets, different methods for different touch events etc.) in your method also.
So, I think the MenuItemImage is better in your case:
bool flag = true;
MenuItemImage *button = MenuItemImage::create("play.png", "play_pressed.png", CC_CALLBACK_0(Gallery::playSong, this));
button->setPosition(Vec2((visibleSize.width/2)+origin.x,(visibleSize.height/2)+origin.y-80)); // better is use Vec2, Point can be ambiguous
Menu* menu = Menu::create(button, NULL); // add created button on Menu
menu ->setPosition(0,0);
this->addChild(menu);
And then set the images in handler pressing:
void Gallery::playSong()
{
if(flag)
{
// preload better move to AppDelegate.cpp
// CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("1.mp3");
flag = false;
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("1.mp3");
button->setNormalImage(Sprite::create(“pause.png”));
button->setSelectedImage(Sprite::create(“pause_pressed.png”)); // if you use selected image
}
else
{
flag = true;
CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
button->setNormalImage(Sprite::create(“play.png”));
button->setSelectedImage(Sprite::create(“play_pressed.png”));
}
}
In cocos 3.x use property: setHighlighted(bool)
Example:
When press a key: button->setHighlighted(true);
When release the key:
button->setHighlighted(false);

Visual C++ Detect a Right Click on a Button

I have a program where I want a right click on a button to do a completely different amount of code. I have the code display a messagebox for the example, but eventually it will just be a method call each. I'll show you the context in which I need it. Any and all help on how to detect a right click will help. Here's the snippet of code I have:
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
String^ buttonName = safe_cast<Button^>(sender)->Name;
safe_cast<Button^>(sender)->Enabled = false;
if(/*Insert Code Here To Detect a right click*/)
MessageBox::Show("Right Click");
else
MessageBox::Show("Left Click");
MessageBox::Show(buttonName);
}
};
You can use the MouseDown event and check if it is right
void button1_MouseDown( Object^ /*sender*/, System::Windows::Forms::MouseEventArgs^ e )
{
// Update the mouse path with the mouse information
Point mouseDownLocation = Point(e->X,e->Y);
String^ eventString = nullptr;
switch ( e->Button )
{
case ::MouseButtons::Left:
eventString = "L";
break;
case ::MouseButtons::Right:
eventString = "R";
break;
case ::MouseButtons::Middle:
eventString = "M";
break;
case ::MouseButtons::XButton1:
eventString = "X1";
break;
case ::MouseButtons::XButton2:
eventString = "X2";
break;
case ::MouseButtons::None:
default:
break;
}
//Process Here...
}

SFML2 Mouse::isButtonPressed filling up event queue

First of all I'd like to say that I'm not sure if the title is appropriate but it's the only logical explanation I could find.
What I'm trying to do is move my window by clicking a sprite (sort of like simulating a titlebar).
All working fine until I let go of the mouse button the rate new mouse events are emitted is way lower and with huge 1.5~2s pauses between them.
Is it possible that sf::Mouse::isBUttonPressed is filling the queue or is it another issue?
Edit: The window class has a sf::Event object and passes it to each object's event handler.
The sprite class has an event handler of this form:
bool object::handleEvents(sf::Event& event)
{
switch(event.type)
{
case sf::Event::MouseMoved:
case sf::Event::MouseButtonPressed:
case sf::Event::MouseButtonReleased:
{
auto mouse_pos = sf::Mouse::getPosition(*this->parent);
if(this->isPointInside(mouse_pos))
{
if(event.type == sf::Event::MouseMoved)
{
this->hovering = true;
if(this->callback["onHover"])
this->callback["onHover"](this, nullptr);
return true;
}
else if(event.type == sf::Event::MouseButtonPressed)
{
this->clicked = true;
this->focused = true;
if(event.mouseButton.button == sf::Mouse::Left)
if(this->callback["onLClick"])
this->callback["onLClick"](this, ref(mouse_pos));
if(event.mouseButton.button == sf::Mouse::Right)
if(this->callback["onRClick"])
this->callback["onRClick"](this, ref(mouse_pos));
return true;
}
else if(event.type == sf::Event::MouseButtonReleased && this->clicked)
{
this->clicked = false;
if(event.mouseButton.button == sf::Mouse::Left)
if(this->callback["onLClickReleased"])
this->callback["onLClickReleased"](this, ref(mouse_pos));
if(event.mouseButton.button == sf::Mouse::Right)
if(this->callback["onRClickReleased"])
this->callback["onRClickReleased"](this, ref(mouse_pos));
return true;
}
}
else
{
if(this->hovering)
{
if(this->callback["onHoverLost"])
this->callback["onHoverLost"](this, nullptr);
this->hovering = false;
}
}
}break;
default: ;
}
return false;
}
and the code responsible for moving the window:
titlebar->callback["onLClick"] = [&](object* obj, void* data)
{
sf::Vector2i* relpos = (sf::Vector2i*)(data);
while(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2i abspos = sf::Mouse::getPosition();
window.setPosition(sf::Vector2i((abspos.x - relpos->x),(abspos.y - relpos->y)));
}
titlebar->clicked = false;
};
The sf::Mouse class as well as sf::Keyboard and sf::Joystick aren't connected to the event system, but are completely independent, thus it's impossible that isButtonPressed would've any influence on the events.
The real problem in your code is the 'infinite' loop when the left mouse button is pressed. If the left mouse button is pressed, everything that happens in your application is, that the window gets moved around. There won't be any event dispatches (= processing) and every event that happens within that time, will get pilled in the event queue. Thus when you return to process the events, you'll have a longer queue than usual and will start dispatching with the oldest event.
So if you now move your window around for 2 seconds, you'll get a filled queue worth 2 seconds which can delay the further processing.
To solve this problem, you'll most probably have to dispatch all the events while you're moving the window.

Getting mouse events from HIDManager in OSX with C++

I'm porting a game from pc to osx and I'm getting stuck with input events. The main game window is a cocoa app that interfaces with a C++ backend. The pc code uses DirectInput and windows messages to generate keyboard and mouse events that the game understands.
When I first started the port I replaced the windows messages with Carbon event handling, but since discovered that Cocoa apps don't fire off carbon events. I did a bit more reading and discovered the HIDManager which seemed to do what I want and was accessible from c++. Using the information in the post here Using IOHIDManager to Get Modifier Key Events I managed to get keyboard input working, but have so far been unable to extend the example code to generate mouse events as well. The code is have is as follows:
void myHIDCallback(void* context, IOReturn result, void* sender, IOHIDValueRef value)
{
IOHIDElementRef elem = IOHIDValueGetElement(value);
if (IOHIDElementGetUsagePage(elem) == 0x07)
{
// Keyboard events
card32 scancode = IOHIDElementGetUsage(elem);
if (scancode >= 4 && scancode <= 231)
{
long pressed = IOHIDValueGetIntegerValue(value);
KEY_EVENT_DETAILS details = { KEY_EVENT_NONE, NUM_KEYS };
for (card32 n=0; n<NUM_KEYS; ++n)
{
if (n_direct_input_mappings[n].direct_input_key == scancode)
{
details.key_type = n_direct_input_mappings[n].key;
break;
}
}
switch (pressed)
{
case 0:
details.event_type = KEY_EVENT_KEY_DOWN;
break;
case 1:
details.event_type = KEY_EVENT_KEY_UP;
break;
}
sApplication->handle_key_event(details);
}
}
else
if (IOHIDElementGetUsagePage(elem) == 0x02)
{
// Mouse events
card32 usage = IOHIDElementGetUsage(elem);
long pressed = IOHIDValueGetIntegerValue(value);
}
else
{
}
}
CFMutableDictionaryRef myCreateDeviceMatchingDictionary(UInt32 usagePage, UInt32 usage)
{
CFMutableDictionaryRef ret = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (ret)
{
CFNumberRef pageNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage);
if (pageNumberRef)
{
CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsagePageKey), pageNumberRef);
CFRelease(pageNumberRef);
CFNumberRef usageNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
if (usageNumberRef)
{
CFDictionarySetValue(ret, CFSTR(kIOHIDDeviceUsageKey), usageNumberRef);
CFRelease(usageNumberRef);
return ret;
}
}
CFRelease(ret);
}
return NULL;
}
bool acquire_hardware_controllers(CA::Application& app, CAWindow& window_handle)
{
sApplication = &app;
// Setup the keyboard event handler
sHIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
IOHIDManagerOpen(sHIDManager, kIOHIDOptionsTypeNone);
CFMutableDictionaryRef mouse = myCreateDeviceMatchingDictionary(0x01, 2);
CFMutableDictionaryRef keyboard = myCreateDeviceMatchingDictionary(0x01, 6);
CFMutableDictionaryRef keypad = myCreateDeviceMatchingDictionary(0x01, 7);
CFMutableDictionaryRef matchesList[] = {
keyboard,
keypad,
mouse
};
CFArrayRef matches = CFArrayCreate(kCFAllocatorDefault, (const void**)matchesList, 3, NULL);
IOHIDManagerSetDeviceMatchingMultiple(sHIDManager, matches);
IOHIDManagerRegisterInputValueCallback(sHIDManager, myHIDCallback, NULL);
IOHIDManagerScheduleWithRunLoop(sHIDManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
}
If anyone can help me out then that would be great. If I can't get this working then I guess I can move over to Cocoa event handling, but the pc code also has some keyboard and mouse polling that I was hoping to implement as well, and I'm not sure that Cocoa supports polling keyboard state - although I will be happy to be corrected.
TIA.