Qt Editor: Fix viewport focus and keyboard handling.

qteditor
Sven Eberhardt 2016-03-15 22:58:41 -04:00
parent f6ce50e9e7
commit 645520c7af
7 changed files with 213 additions and 85 deletions

View File

@ -82,12 +82,10 @@ public:
#ifdef WITH_QT_EDITOR
void Execute();
void AddViewport(C4ViewportWindow *cvp);
void OnViewportActiveChanged(C4ViewportWindow *cvp, bool is_active);
void OnObjectSelectionChanged(class C4EditCursorSelection &selection); // selection changed (through other means than creator or object list view)
#else
void Execute() { }
void AddViewport(C4ViewportWindow *cvp) { }
void OnViewportActiveChanged(C4ViewportWindow *cvp, bool is_active) { }
void OnObjectSelectionChanged(class C4EditCursorSelection &selection) { }
#endif

View File

@ -335,12 +335,6 @@ void C4ConsoleGUI::UpdateMenuText(HMENU hMenu) { /* Translation done through QTr
state->AddViewport(cvp);
}
void C4ConsoleGUI::OnViewportActiveChanged(C4ViewportWindow *cvp, bool is_active)
{
// Reflect viewport activation in GUI
state->OnViewportActiveChanged(cvp, is_active);
}
void C4ConsoleGUI::OnObjectSelectionChanged(class C4EditCursorSelection &selection)
{
// selection changed (through other means than creator or object list view)

View File

@ -42,8 +42,6 @@ QString C4ConsoleQtTranslator::translate(const char * context, const char * sour
C4ConsoleQtTranslator qt_translator;
/* Kick client action */
C4ConsoleClientAction::C4ConsoleClientAction(int32_t client_id, const char *text, QObject *parent)
@ -118,22 +116,19 @@ C4ConsoleQtMainWindow::C4ConsoleQtMainWindow(C4AbstractApp *app, C4ConsoleGUISta
#endif
}
#ifdef USE_WIN32_WINDOWS
bool ConsoleHandleWin32KeyboardMessage(MSG *msg); // in C4WindowWin32.cpp
#endif
bool C4ConsoleQtMainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
void C4ConsoleQtMainWindow::keyPressEvent(QKeyEvent * event)
{
#ifdef USE_WIN32_WINDOWS
MSG *msg = static_cast<MSG*>(message);
if (ConsoleHandleWin32KeyboardMessage(msg)) return true;
#else
TODO: Should implement this through native Qt keyboard signals instead of Win32 only
#endif
// Handle by Qt
return false;
if (HandleEditorKeyDown(event)) event->setAccepted(true);
QMainWindow::keyPressEvent(event);
}
void C4ConsoleQtMainWindow::keyReleaseEvent(QKeyEvent * event)
{
if (HandleEditorKeyUp(event)) event->setAccepted(true);
QMainWindow::keyPressEvent(event);
}
void C4ConsoleQtMainWindow::closeEvent(QCloseEvent *event)
{
QMainWindow::closeEvent(event);
@ -311,6 +306,34 @@ void C4ConsoleQtMainWindow::OnObjectListSelectionChanged(const QItemSelection &
state->OnObjectListSelectionChanged(selected, deselected);
}
bool C4ConsoleQtMainWindow::HandleEditorKeyDown(QKeyEvent *event)
{
switch (event->key())
{
case Qt::Key_Delete:
::Console.EditCursor.Delete();
return true;
}
uint32_t shift = 0;
if (event->modifiers() & Qt::AltModifier) shift |= MK_ALT;
if (event->modifiers() & Qt::ControlModifier) shift |= MK_CONTROL;
if (event->modifiers() & Qt::ShiftModifier) shift |= MK_SHIFT;
::Console.EditCursor.KeyDown(event->nativeScanCode(), shift);
// key not handled (ignore shift handling done in EditCursor)
return false;
}
bool C4ConsoleQtMainWindow::HandleEditorKeyUp(QKeyEvent *event)
{
uint32_t shift = 0;
if (event->modifiers() & Qt::AltModifier) shift |= MK_ALT;
if (event->modifiers() & Qt::ControlModifier) shift |= MK_CONTROL;
if (event->modifiers() & Qt::ShiftModifier) shift |= MK_SHIFT;
::Console.EditCursor.KeyUp(event->nativeScanCode(), shift);
// key not handled (ignore shift handling done in EditCursor)
return false;
}
@ -548,22 +571,12 @@ void C4ConsoleGUIState::ClearViewportMenu()
void C4ConsoleGUIState::AddViewport(C4ViewportWindow *cvp)
{
if (!viewport_area) return;
C4ConsoleQtViewportDockWidget *new_viewport = new C4ConsoleQtViewportDockWidget(viewport_area, cvp);
C4ConsoleQtViewportDockWidget *new_viewport = new C4ConsoleQtViewportDockWidget(window.get(), viewport_area, cvp);
viewport_area->addDockWidget(Qt::BottomDockWidgetArea, new_viewport);
viewports.push_back(new_viewport);
new_viewport->setFocus();
}
void C4ConsoleGUIState::OnViewportActiveChanged(C4ViewportWindow *cvp, bool is_active)
{
// Viewport active state changed: Forward to appropriate viewport window
for (auto vp : viewports)
if (vp->GetViewportWindow() == cvp)
{
vp->OnActiveChanged(is_active);
}
}
void C4ConsoleGUIState::SetInputFunctions(std::list<const char*> &functions)
{
SetComboItems(ui.consoleInputBox, functions);

View File

@ -87,7 +87,8 @@ class C4ConsoleQtMainWindow : public QMainWindow
class C4ConsoleGUIState *state;
protected:
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
void keyPressEvent(QKeyEvent * event) override;
void keyReleaseEvent(QKeyEvent * event) override;
public:
C4ConsoleQtMainWindow(class C4AbstractApp *app, class C4ConsoleGUIState *state);
@ -132,6 +133,9 @@ public:
void OnCreatorSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected);
void OnCreatorCurrentChanged(const QModelIndex & current, const QModelIndex & previous);
void OnObjectListSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected);
// Global editor key processing
bool HandleEditorKeyDown(QKeyEvent *event);
bool HandleEditorKeyUp(QKeyEvent *event);
};
@ -195,7 +199,6 @@ public:
void AddPlayerViewportMenuItem(int32_t plr, const char *text);
void ClearViewportMenu();
void AddViewport(class C4ViewportWindow *cvp);
void OnViewportActiveChanged(C4ViewportWindow *cvp, bool is_active);
void SetInputFunctions(std::list<const char*> &functions);
void PropertyDlgUpdate(C4EditCursorSelection &rSelection, bool force_function_update);
void ReInitDefinitions();

View File

@ -19,6 +19,7 @@
#include <C4Include.h>
#include <C4Value.h>
#include <C4ConsoleQtViewport.h>
#include <C4ConsoleQtState.h>
#include <C4Viewport.h>
#include <C4ViewportWindow.h>
#include <C4Console.h>
@ -35,7 +36,7 @@ C4ConsoleQtViewportView::C4ConsoleQtViewportView(class C4ConsoleQtViewportDockWi
setAttribute(Qt::WA_NativeWindow, true);
setAttribute(Qt::WA_ShowWithoutActivating, true);
setWindowFlags(Qt::FramelessWindowHint);
setFocusPolicy(Qt::TabFocus);
setFocusPolicy(Qt::WheelFocus);
setMouseTracking(true);
// Register for viewport
#ifdef USE_WIN32_WINDOWS
@ -123,6 +124,7 @@ void C4ConsoleQtViewportView::mouseMoveEvent(QMouseEvent *eventMove)
}
else
{
this->setCursor(Qt::CrossCursor);
cvp->pWindow->EditCursorMove(eventMove->x(), eventMove->y(), GetShiftWParam());
}
@ -203,46 +205,162 @@ void C4ConsoleQtViewportView::wheelEvent(QWheelEvent *event)
}
}
C4ConsoleQtViewportDockWidget::C4ConsoleQtViewportDockWidget(QMainWindow *parent, C4ViewportWindow *cvp)
: QDockWidget("", parent), cvp(cvp)
void C4ConsoleQtViewportView::focusInEvent(QFocusEvent * event)
{
// Translated title
setWindowTitle(LoadResStr("IDS_CNS_VIEWPORT"));
// Actual view container
view = new C4ConsoleQtViewportView(this);
setWidget(view);
connect(this, SIGNAL(dockLocationChanged(bool)), this, SLOT(DockLocationChanged(bool)));
OnActiveChanged(true);
dock->OnActiveChanged(true);
QWidget::focusInEvent(event);
}
void C4ConsoleQtViewportDockWidget::OnActiveChanged(bool active)
void C4ConsoleQtViewportView::focusOutEvent(QFocusEvent * event)
{
dock->OnActiveChanged(false);
QWidget::focusOutEvent(event);
}
/* Keyboard scan code mapping from Qt to our keys */
/** Convert certain keys to (unix(?)) scancodes (those that differ from scancodes on Windows. Sometimes. Maybe.) */
static C4KeyCode QtKeyToUnixScancode(const QKeyEvent &event)
{
//LogF("VK: %x SC: %x key: %x", event.nativeVirtualKey(), event.nativeScanCode(), event.key());
// Map some special keys
switch (event.key())
{
case Qt::Key_Home: return K_HOME;
case Qt::Key_End: return K_END;
case Qt::Key_PageUp: return K_PAGEUP;
case Qt::Key_PageDown: return K_PAGEDOWN;
case Qt::Key_Up: return K_UP;
case Qt::Key_Down: return K_DOWN;
case Qt::Key_Left: return K_LEFT;
case Qt::Key_Right: return K_RIGHT;
case Qt::Key_Clear: return K_CENTER;
case Qt::Key_Insert: return K_INSERT;
case Qt::Key_Delete: return K_DELETE;
case Qt::Key_Menu: return K_MENU;
case Qt::Key_Pause: return K_PAUSE;
case Qt::Key_Print: return K_PRINT;
case Qt::Key_NumLock: return K_NUM;
default:
// Some native Win32 key mappings...
#ifdef USE_WIN32_WINDOWS
switch (event.nativeVirtualKey())
{
case VK_LWIN: return K_WIN_L;
case VK_RWIN: return K_WIN_R;
case VK_NUMPAD1: return K_NUM1;
case VK_NUMPAD2: return K_NUM2;
case VK_NUMPAD3: return K_NUM3;
case VK_NUMPAD4: return K_NUM4;
case VK_NUMPAD5: return K_NUM5;
case VK_NUMPAD6: return K_NUM6;
case VK_NUMPAD7: return K_NUM7;
case VK_NUMPAD8: return K_NUM8;
case VK_NUMPAD9: return K_NUM9;
case VK_NUMPAD0: return K_NUM0;
}
switch (event.nativeScanCode())
{
case 285: return K_CONTROL_R;
}
#endif
// Otherwise rely on native scan code to be the same on all platforms
return event.nativeScanCode();
}
}
void C4ConsoleQtViewportView::keyPressEvent(QKeyEvent * event)
{
// Convert key to our internal mapping
C4KeyCode code = QtKeyToUnixScancode(*event);
// Handled if handled as player control or main editor
bool handled = Game.DoKeyboardInput(code, KEYEV_Down, !!(event->modifiers() & Qt::AltModifier), !!(event->modifiers() & Qt::ControlModifier), !!(event->modifiers() & Qt::ShiftModifier), event->isAutoRepeat(), NULL);
if (!handled) handled = dock->main_window->HandleEditorKeyDown(event);
event->setAccepted(handled);
}
void C4ConsoleQtViewportView::keyReleaseEvent(QKeyEvent * event)
{
// Convert key to our internal mapping
C4KeyCode code = QtKeyToUnixScancode(*event);
// Handled if handled as player control
bool handled = Game.DoKeyboardInput(code, KEYEV_Up, !!(event->modifiers() & Qt::AltModifier), !!(event->modifiers() & Qt::ControlModifier), !!(event->modifiers() & Qt::ShiftModifier), event->isAutoRepeat(), NULL);
if (!handled) handled = dock->main_window->HandleEditorKeyUp(event);
event->setAccepted(handled);
}
C4ConsoleQtViewportLabel::C4ConsoleQtViewportLabel(const QString &title, C4ConsoleQtViewportDockWidget *dock)
: QLabel(dock), dock(dock)
{
OnActiveChanged(false);
setText(title);
}
void C4ConsoleQtViewportLabel::OnActiveChanged(bool active)
{
// set color schemes for inactive / active viewport headers
QColor bgclr = QApplication::palette(this).color(QPalette::Highlight);
QColor fontclr = QApplication::palette(this).color(QPalette::HighlightedText);
if (active)
setStyleSheet(QString(
"QDockWidget::title { background: %1; padding: 5px; } QDockWidget { color: %2; font-weight: bold; }")
"QLabel { background: %1; padding: 3px; color: %2; font-weight: bold; }")
.arg(bgclr.name(), fontclr.name()));
else
setStyleSheet("");
setStyleSheet(QString(
"QLabel { padding: 3px; }"));
}
void C4ConsoleQtViewportDockWidget::focusInEvent(QFocusEvent * event)
void C4ConsoleQtViewportLabel::mousePressEvent(QMouseEvent *eventPress)
{
OnActiveChanged(true);
QDockWidget::focusInEvent(event);
dock->view->setFocus();
QLabel::mousePressEvent(eventPress);
}
void C4ConsoleQtViewportDockWidget::focusOutEvent(QFocusEvent * event)
C4ConsoleQtViewportDockWidget::C4ConsoleQtViewportDockWidget(C4ConsoleQtMainWindow *main_window, QMainWindow *parent, C4ViewportWindow *cvp)
: QDockWidget("", parent), main_window(main_window), cvp(cvp)
{
OnActiveChanged(false);
QDockWidget::focusOutEvent(event);
// Translated title
setWindowTitle(LoadResStr("IDS_CNS_VIEWPORT"));
// Actual view container
view = new C4ConsoleQtViewportView(this);
setTitleBarWidget((title_label = new C4ConsoleQtViewportLabel(windowTitle(), this)));
setWidget(view);
connect(this, SIGNAL(topLevelChanged(bool)), this, SLOT(TopLevelChanged(bool)));
}
void C4ConsoleQtViewportDockWidget::DockLocationChanged(Qt::DockWidgetArea new_area)
void C4ConsoleQtViewportDockWidget::mousePressEvent(QMouseEvent *eventPress)
{
// Re-docked:
// Clicking the dock focuses the viewport
view->setFocus();
QDockWidget::mousePressEvent(eventPress);
}
void C4ConsoleQtViewportDockWidget::OnActiveChanged(bool active)
{
title_label->OnActiveChanged(active);
}
void C4ConsoleQtViewportDockWidget::TopLevelChanged(bool is_floating)
{
if (!is_floating)
{
// docked has custom title
setTitleBarWidget(title_label);
}
else
{
// undocked using OS title
setTitleBarWidget(NULL);
}
// Ensure focus after undock and after re-docking floating viewport window
view->setFocus();
}
void C4ConsoleQtViewportDockWidget::closeEvent(QCloseEvent * event)
@ -255,21 +373,3 @@ void C4ConsoleQtViewportDockWidget::closeEvent(QCloseEvent * event)
deleteLater();
}
}
#ifdef USE_WIN32_WINDOWS
bool ConsoleHandleWin32KeyboardMessage(MSG *msg); // in C4WindowWin32.cpp
#endif
bool C4ConsoleQtViewportDockWidget::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
// Handle keyboard messages on detached viewport windows
#ifdef USE_WIN32_WINDOWS
MSG *msg = static_cast<MSG*>(message);
if (ConsoleHandleWin32KeyboardMessage(msg)) return true;
#else
TODO: Should implement this through native Qt keyboard signals
#endif
// Handle by Qt
return false;
}

View File

@ -35,6 +35,8 @@ private:
bool IsPlayViewport() const;
protected:
void focusInEvent(QFocusEvent * event) override;
void focusOutEvent(QFocusEvent * event) override;
void resizeEvent(QResizeEvent *resize_event) override;
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
void mouseMoveEvent(QMouseEvent *eventMove) override;
@ -42,34 +44,52 @@ protected:
void mouseDoubleClickEvent(QMouseEvent *eventPress) override;
void mouseReleaseEvent(QMouseEvent *releaseEvent) override;
void wheelEvent(QWheelEvent *event) override;
void keyPressEvent(QKeyEvent * event) override;
void keyReleaseEvent(QKeyEvent * event) override;
public:
C4ConsoleQtViewportView(class C4ConsoleQtViewportDockWidget *dock);
};
class C4ConsoleQtViewportLabel : public QLabel
{
Q_OBJECT
class C4ConsoleQtViewportDockWidget *dock;
bool active;
QPalette pal_inactive, pal_active;
public:
C4ConsoleQtViewportLabel(const QString &title, C4ConsoleQtViewportDockWidget *dock);
void OnActiveChanged(bool active);
protected:
void mousePressEvent(QMouseEvent *eventPress) override;
};
class C4ConsoleQtViewportDockWidget : public QDockWidget
{
Q_OBJECT
class C4ConsoleQtMainWindow *main_window;
class C4ViewportWindow *cvp;
C4ConsoleQtViewportView *view;
QPalette pal_inactive, pal_active;
C4ConsoleQtViewportLabel *title_label;
protected:
void focusInEvent(QFocusEvent * event) override;
void focusOutEvent(QFocusEvent * event) override;
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
void mousePressEvent(QMouseEvent *eventPress);
void OnActiveChanged(bool active);
public:
C4ConsoleQtViewportDockWidget(class QMainWindow *parent, class C4ViewportWindow *window);
C4ConsoleQtViewportDockWidget(class C4ConsoleQtMainWindow *main_window, QMainWindow *parent, class C4ViewportWindow *window);
virtual void closeEvent(QCloseEvent * event);
void OnActiveChanged(bool active);
class C4ViewportWindow *GetViewportWindow() const { return cvp; }
private slots :
void DockLocationChanged(Qt::DockWidgetArea new_area);
void TopLevelChanged(bool is_floating);
friend C4ConsoleQtViewportView;
friend C4ConsoleQtViewportLabel;
};

View File

@ -75,7 +75,7 @@ bool SetRegistryString(const char *szSubKey,
if ((qerr=RegCreateKeyExW(HKEY_CURRENT_USER,
GetWideChar(szSubKey),
0,
L"",
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
@ -131,7 +131,7 @@ static bool SetRegClassesRoot(const wchar_t *szSubKey,
if ((qerr=RegCreateKeyExW(HKEY_CLASSES_ROOT,
szSubKey,
0,
L"",
NULL,
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
@ -391,7 +391,7 @@ void StdCompilerConfigWrite::CreateKey(HKEY hParent)
// Open/Create registry key
if (RegCreateKeyExW(hParent ? hParent : pKey->Parent->Handle,
pKey->Name.GetWideChar(),
0, L"", REG_OPTION_NON_VOLATILE,
0, NULL, REG_OPTION_NON_VOLATILE,
KEY_WRITE, NULL,
&pKey->Handle, NULL) != ERROR_SUCCESS)
excCorrupt("Could not create key %s!", pKey->Name.getData());