void Window::SetEnabled(bool enabled) { AssertThread(); const bool was_focused = !enabled && HasFocus(); ::EnableWindow(hWnd, enabled); if (was_focused && ::GetFocus() == NULL) { /* The window lost its keyboard focus because it got disabled; now the focus is in limbo, and can only be recovered by clicking on another control, which is impossible for Altair users (no touch screen). This is a major WIN32 API misdesign that is documtented here: https://blogs.msdn.com/b/oldnewthing/archive/2004/08/04/208005.aspx */ ContainerWindow *root = GetRootOwner(); if (root != NULL) /* to work around this problem, we pass focus to the main window, which will bounce it to the next dialog control; this kludge is needed because this Window doesn't know the dialog code, and trusts that the main window will do the right thing */ root->SetFocus(); } }
ProgressWindow::ProgressWindow(ContainerWindow &parent) { set(parent, InfoBoxLayout::landscape ? (LPCTSTR)IDD_PROGRESS_LANDSCAPE : (LPCTSTR)IDD_PROGRESS); TCHAR Temp[1024]; _stprintf(Temp, _T("%s %s"), gettext(_T("Version")), XCSoar_Version); set_item_text(IDC_VERSION, Temp); #ifdef WINDOWSPC RECT rc = parent.get_client_rect(); RECT rcp = get_client_rect(); move(rc.left, rc.top, rcp.right - rcp.left, rcp.bottom - rcp.top); #else #ifndef GNAV SHFullScreen(hWnd, SHFS_HIDETASKBAR|SHFS_HIDESIPBUTTON|SHFS_HIDESTARTICON); #endif #endif insert_after(HWND_TOP, true); set_range(0, 100); set_step(5); #ifndef ENABLE_SDL ::SetForegroundWindow(hWnd); #endif /* !ENABLE_SDL */ update(); }
ProgressWindow::ProgressWindow(ContainerWindow &parent) :background_color(COLOR_WHITE), background_brush(background_color), position(0) { PixelRect rc = parent.GetClientRect(); WindowStyle style; style.Hide(); Create(parent, rc, style); const unsigned width = rc.right - rc.left, height = rc.bottom - rc.top; // Load progress bar background bitmap_progress_border.Load(IDB_PROGRESSBORDER); // Determine text height #ifndef USE_GDI font.Load(FontDescription(Layout::FontScale(10))); text_height = font.GetHeight(); #else VirtualCanvas canvas({1, 1}); text_height = canvas.GetFontHeight(); #endif // Make progress bar height proportional to window height const unsigned progress_height = height / 20; const unsigned progress_horizontal_border = progress_height / 2; progress_border_height = progress_height * 2; // Initialize message text field PixelRect message_rc = rc; message_rc.bottom -= progress_border_height + height / 48; message_rc.top = message_rc.bottom - text_height; TextWindowStyle message_style; message_style.center(); message.Create(*this, NULL, message_rc, message_style); #ifndef USE_GDI message.SetFont(font); #endif // Initialize progress bar PixelRect pb_rc; pb_rc.left = progress_horizontal_border; pb_rc.right = pb_rc.left + width - progress_height; pb_rc.top = height - progress_border_height + progress_horizontal_border; pb_rc.bottom = pb_rc.top + progress_height; ProgressBarStyle pb_style; progress_bar.Create(*this, pb_rc, pb_style); message.InstallWndProc(); // needed for OnChildColor() // Set progress bar step size and range SetRange(0, 1000); SetStep(50); // Show dialog ShowOnTop(); }
ProgressWindow::ProgressWindow(ContainerWindow &parent) :background_color(COLOR_WHITE), background_brush(background_color), position(0) { PixelRect rc = parent.get_client_rect(); WindowStyle style; style.hide(); set(parent, rc.left, rc.top, rc.right, rc.bottom, style); unsigned width = rc.right - rc.left, height = rc.bottom - rc.top; // Load progress bar background bitmap_progress_border.load(IDB_PROGRESSBORDER); // Determine text height #ifdef ENABLE_SDL font.set("Droid Sans", 12); text_height = font.get_height(); #else VirtualCanvas canvas(1, 1); text_height = canvas.text_height(_T("W")); #endif // Make progress bar height proportional to window height unsigned progress_height = height / 20; unsigned progress_horizontal_border = progress_height / 2; progress_border_height = progress_height * 2; // Initialize message text field TextWindowStyle message_style; message_style.center(); message.set(*this, NULL, 0, height - progress_border_height - text_height - (height/48), width, text_height, message_style); #ifdef ENABLE_SDL message.set_font(font); #endif // Initialize progress bar ProgressBarStyle pb_style; progress_bar.set(*this, progress_horizontal_border, height - progress_border_height + progress_horizontal_border, width - progress_height, progress_height, pb_style); message.install_wndproc(); // needed for on_color() // Set progress bar step size and range set_range(0, 1000); set_step(50); // Show dialog show_on_top(); update(); }
TabBarControl::TabBarControl(ContainerWindow &_parent, const DialogLook &look, PixelRect tab_rc, const WindowStyle style, bool vertical) :tab_display(nullptr) { Create(_parent, _parent.GetClientRect(), style); tab_display = new TabDisplay(*this, look, *this, tab_rc, vertical); pager.Move(MakePagerRect(GetClientRect(), tab_rc, vertical)); }
Window * ContainerWindow::FindPreviousControl(Window *reference) { assert(reference != NULL); if (reference == this) return NULL; while (true) { ContainerWindow *container = reference->parent; assert(container != NULL); Window *control = container->FindPreviousChildControl(reference); if (control != NULL) return control; if (container == this) return NULL; reference = container; } }
MenuBar::MenuBar(ContainerWindow &parent, const ButtonLook &look) { const PixelRect rc = parent.GetClientRect(); WindowStyle style; style.Hide(); style.Border(); for (unsigned i = 0; i < MAX_BUTTONS; ++i) { PixelRect button_rc = GetButtonPosition(i, rc); buttons[i].Create(parent, look, _T(""), button_rc, style); } }
Window * ContainerWindow::find_next_control(Window *reference) { assert(reference != NULL); if (reference == this) return NULL; while (true) { ContainerWindow *container = reference->parent; assert(container != NULL); Window *control = container->find_next_child_control(reference); if (control != NULL) return control; if (container == this) return NULL; reference = container; } }
MenuBar::MenuBar(ContainerWindow &parent) { const PixelRect rc = parent.get_client_rect(); ButtonWindowStyle style; style.Hide(); style.Border(); style.multiline(); for (unsigned i = 0; i < MAX_BUTTONS; ++i) { PixelRect button_rc = GetButtonPosition(i, rc); buttons[i].set(parent, _T(""), button_rc, style); } }
MenuBar::MenuBar(ContainerWindow &parent) { const RECT rc = parent.get_client_rect(); int x, y, xsize, ysize; ButtonWindowStyle style; style.hide(); style.border(); style.multiline(); for (unsigned i = 0; i < MAX_BUTTONS; ++i) { GetButtonPosition(i, rc, &x, &y, &xsize, &ysize); buttons[i].set(parent, _T(""), i, x, y, xsize, ysize, style); } }
int WndForm::ShowModal() { assert_none_locked(); #define OPENCLOSESUPPRESSTIME 500 #ifndef USE_GDI ContainerWindow *root = get_root_owner(); WindowReference old_focus_reference = root->GetFocusedWindowReference(); #else HWND oldFocusHwnd; #endif /* USE_GDI */ PeriodClock enter_clock; if (is_embedded() && !is_altair()) enter_clock.update(); show_on_top(); mModalResult = 0; #ifdef USE_GDI oldFocusHwnd = ::GetFocus(); if (oldFocusHwnd != NULL) ::SendMessage(oldFocusHwnd, WM_CANCELMODE, 0, 0); #endif /* USE_GDI */ set_focus(); focus_first_control(); bool hastimed = false; WndForm::timeAnyOpenClose.update(); // when current dlg opens or child closes main_window.add_dialog(this); #ifndef USE_GDI main_window.refresh(); #endif #ifdef ANDROID EventLoop loop(*event_queue, main_window); Event event; #elif defined(ENABLE_SDL) EventLoop loop(main_window); SDL_Event event; #else DialogEventLoop loop(*this); MSG event; #endif while ((mModalResult == 0 || force) && loop.get(event)) { #if defined(ENABLE_SDL) && !defined(ANDROID) if (event.type == SDL_QUIT) { mModalResult = mrCancel; continue; } #endif if (!main_window.FilterEvent(event, this)) continue; // hack to stop exiting immediately if (is_embedded() && !is_altair() && !hastimed && is_user_input(event)) { if (!enter_clock.check(200)) /* ignore user input in the first 200ms */ continue; else hastimed = true; } if (is_embedded() && is_mouse_up(event) && !timeAnyOpenClose.check(OPENCLOSESUPPRESSTIME)) /* prevents child click from being repeat-handled by parent if buttons overlap */ continue; if (mOnKeyDownNotify != NULL && is_key_down(event) && #ifdef USE_GDI identify_descendant(event.hwnd) && #endif !check_special_key(this, event) && mOnKeyDownNotify(*this, get_key_code(event))) continue; #if defined(ENABLE_SDL) && !defined(ANDROID) if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_TAB) { /* the Tab key moves the keyboard focus */ const Uint8 *keystate = ::SDL_GetKeyState(NULL); event.key.keysym.sym = keystate[SDLK_LSHIFT] || keystate[SDLK_RSHIFT] ? SDLK_UP : SDLK_DOWN; } #endif if (is_key_down(event) && #ifdef USE_GDI identify_descendant(event.hwnd) && #endif (get_key_code(event) == VK_UP || get_key_code(event) == VK_DOWN)) { /* VK_UP and VK_DOWN move the focus only within the current control group - but we want it to behave like Shift-Tab and Tab */ if (!check_key(this, event)) { /* this window doesn't handle VK_UP/VK_DOWN */ if (get_key_code(event) == VK_DOWN) focus_next_control(); else focus_previous_control(); continue; } } #ifndef USE_GDI if (is_key_down(event) && get_key_code(event) == VK_ESCAPE) { mModalResult = mrCancel; continue; } #endif /* map VK_ESCAPE to mrOK on Altair, because the Escape key is expected to be the one that saves and closes a dialog */ if (is_altair() && is_key_down(event) && get_key_code(event) == VK_ESCAPE) { mModalResult = mrOK; continue; } loop.dispatch(event); } // End Modal Loop main_window.remove_dialog(this); // static. this is current open/close or child open/close WndForm::timeAnyOpenClose.update(); #ifdef USE_GDI SetFocus(oldFocusHwnd); #else if (old_focus_reference.Defined()) { Window *old_focus = old_focus_reference.Get(*root); if (old_focus != NULL) old_focus->set_focus(); } #endif /* !USE_GDI */ return mModalResult; }
int WndForm::ShowModal() { #ifndef USE_WINUSER ContainerWindow *root = GetRootOwner(); WindowReference old_focus_reference = root->GetFocusedWindowReference(); #else HWND oldFocusHwnd; #endif /* USE_WINUSER */ PeriodClock enter_clock; if (IsEmbedded()) enter_clock.Update(); ShowOnTop(); modal_result = 0; SingleWindow &main_window = GetMainWindow(); main_window.CancelMode(); #ifdef USE_WINUSER oldFocusHwnd = ::GetFocus(); #endif /* USE_WINUSER */ SetDefaultFocus(); bool hastimed = false; main_window.AddDialog(this); #ifndef USE_GDI main_window.Refresh(); #endif #if defined(ANDROID) || defined(USE_POLL_EVENT) || defined(ENABLE_SDL) EventLoop loop(*event_queue, main_window); #else DialogEventLoop loop(*event_queue, *this); #endif Event event; while ((modal_result == 0 || force) && loop.Get(event)) { if (!main_window.FilterEvent(event, this)) { if (modeless && event.IsMouseDown()) break; else continue; } // hack to stop exiting immediately if (IsEmbedded() && !hastimed && event.IsUserInput()) { if (!enter_clock.Check(200)) /* ignore user input in the first 200ms */ continue; else hastimed = true; } if (event.IsKeyDown()) { if (OnAnyKeyDown(event.GetKeyCode())) continue; #ifdef ENABLE_SDL if (event.GetKeyCode() == SDLK_TAB) { /* the Tab key moves the keyboard focus */ #if SDL_MAJOR_VERSION >= 2 const Uint8 *keystate = ::SDL_GetKeyboardState(nullptr); event.event.key.keysym.sym = keystate[SDL_SCANCODE_LSHIFT] || keystate[SDL_SCANCODE_RSHIFT] ? SDLK_UP : SDLK_DOWN; #else const Uint8 *keystate = ::SDL_GetKeyState(nullptr); event.event.key.keysym.sym = keystate[SDLK_LSHIFT] || keystate[SDLK_RSHIFT] ? SDLK_UP : SDLK_DOWN; #endif } #endif if ( #ifdef USE_WINUSER IdentifyDescendant(event.msg.hwnd) && #endif (event.GetKeyCode() == KEY_UP || event.GetKeyCode() == KEY_DOWN)) { /* KEY_UP and KEY_DOWN move the focus only within the current control group - but we want it to behave like Shift-Tab and Tab */ if (!CheckKey(this, event)) { /* this window doesn't handle KEY_UP/KEY_DOWN */ if (event.GetKeyCode() == KEY_DOWN) FocusNextControl(); else FocusPreviousControl(); continue; } } #ifndef USE_WINUSER if (event.GetKeyCode() == KEY_ESCAPE) { modal_result = mrCancel; continue; } #endif #ifdef USE_LINUX_INPUT if (event.GetKeyCode() == KEY_POWER) { /* the Kobo power button closes the modal dialog */ modal_result = mrCancel; continue; } #endif } if (character_function && (event.GetCharacterCount() > 0)) { bool handled = false; for (size_t i = 0; i < event.GetCharacterCount(); ++i) handled = character_function(event.GetCharacter(i)) || handled; if (handled) continue; } loop.Dispatch(event); } // End Modal Loop main_window.RemoveDialog(this); #ifdef USE_WINUSER ::SetFocus(oldFocusHwnd); #else if (old_focus_reference.Defined()) { Window *old_focus = old_focus_reference.Get(*root); if (old_focus != nullptr) old_focus->SetFocus(); } #endif /* !USE_WINUSER */ return modal_result; }
int WndForm::ShowModal() { AssertNoneLocked(); #define OPENCLOSESUPPRESSTIME 500 #ifndef USE_GDI ContainerWindow *root = GetRootOwner(); WindowReference old_focus_reference = root->GetFocusedWindowReference(); #else HWND oldFocusHwnd; #endif /* USE_GDI */ PeriodClock enter_clock; if (IsEmbedded() && !IsAltair()) enter_clock.Update(); ShowOnTop(); modal_result = 0; SingleWindow &main_window = GetMainWindow(); main_window.CancelMode(); #ifdef USE_GDI oldFocusHwnd = ::GetFocus(); #endif /* USE_GDI */ SetFocus(); if (default_focus) default_focus->SetFocus(); else client_area.FocusFirstControl(); bool hastimed = false; main_window.AddDialog(this); #ifndef USE_GDI main_window.Refresh(); #endif #if defined(ANDROID) || defined(USE_EGL) EventLoop loop(*event_queue, main_window); #elif defined(ENABLE_SDL) EventLoop loop(main_window); #else DialogEventLoop loop(*this); #endif Event event; while ((modal_result == 0 || force) && loop.Get(event)) { if (!main_window.FilterEvent(event, this)) { if (modeless && event.IsMouseDown()) break; else continue; } // hack to stop exiting immediately if (IsEmbedded() && !IsAltair() && !hastimed && event.IsUserInput()) { if (!enter_clock.Check(200)) /* ignore user input in the first 200ms */ continue; else hastimed = true; } if (event.IsKeyDown()) { if (key_down_function && #ifdef USE_GDI IdentifyDescendant(event.msg.hwnd) && #endif !CheckSpecialKey(this, event) && key_down_function(event.GetKeyCode())) continue; #ifdef ENABLE_SDL if (event.GetKeyCode() == SDLK_TAB) { /* the Tab key moves the keyboard focus */ const Uint8 *keystate = ::SDL_GetKeyState(NULL); event.event.key.keysym.sym = keystate[SDLK_LSHIFT] || keystate[SDLK_RSHIFT] ? SDLK_UP : SDLK_DOWN; } #endif if ( #ifdef USE_GDI IdentifyDescendant(event.msg.hwnd) && #endif (event.GetKeyCode() == KEY_UP || event.GetKeyCode() == KEY_DOWN)) { /* KEY_UP and KEY_DOWN move the focus only within the current control group - but we want it to behave like Shift-Tab and Tab */ if (!CheckKey(this, event)) { /* this window doesn't handle KEY_UP/KEY_DOWN */ if (event.GetKeyCode() == KEY_DOWN) FocusNextControl(); else FocusPreviousControl(); continue; } } #if !defined USE_GDI || defined _WIN32_WCE /* The Windows CE dialog manager does not handle KEY_ESCAPE and so we have to do it by ourself */ // On Altair, the RemoteKey ("E" Button) shall also close the analyse-page if (IsAltair()) { #ifdef GNAV if (event.GetKeyCode() == KEY_ESCAPE || event.GetKeyCode() == KEY_F15) { modal_result = mrOK; continue; } #endif } else if (event.GetKeyCode() == KEY_ESCAPE) { modal_result = mrCancel; continue; } #endif } if (event.IsCharacter() && character_function && character_function(event.GetCharacter())) continue; loop.Dispatch(event); } // End Modal Loop main_window.RemoveDialog(this); #ifdef USE_GDI ::SetFocus(oldFocusHwnd); #else if (old_focus_reference.Defined()) { Window *old_focus = old_focus_reference.Get(*root); if (old_focus != NULL) old_focus->SetFocus(); } #endif /* !USE_GDI */ return modal_result; }