diff options
author | andreykproductengine <andreykproductengine@lindenlab.com> | 2019-10-03 19:46:12 +0300 |
---|---|---|
committer | andreykproductengine <andreykproductengine@lindenlab.com> | 2019-10-03 19:46:12 +0300 |
commit | b8c5ae8d8fcf9219112c4ab48233615732737e44 (patch) | |
tree | db0661d9084100f1e700d868ffe78609ccc0f3f0 /indra/newview/llsetkeybinddialog.cpp | |
parent | b6890180eae59529a5825a47f80c9833c0959352 (diff) |
SL-6109 Better menu accelerator support and slight reorganization
Diffstat (limited to 'indra/newview/llsetkeybinddialog.cpp')
-rw-r--r-- | indra/newview/llsetkeybinddialog.cpp | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/indra/newview/llsetkeybinddialog.cpp b/indra/newview/llsetkeybinddialog.cpp new file mode 100644 index 0000000000..0ad71cb372 --- /dev/null +++ b/indra/newview/llsetkeybinddialog.cpp @@ -0,0 +1,298 @@ +/** + * @file llsetkeybinddialog.cpp + * @brief LLSetKeyBindDialog class implementation. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llsetkeybinddialog.h" + +//#include "llkeyboard.h" + +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "lleventtimer.h" +#include "llfocusmgr.h" + +class LLSetKeyBindDialog::Updater : public LLEventTimer +{ +public: + + typedef boost::function<void(MASK)> callback_t; + + Updater(callback_t cb, F32 period, MASK mask) + :LLEventTimer(period), + mMask(mask), + mCallback(cb) + { + mEventTimer.start(); + } + + virtual ~Updater(){} + +protected: + BOOL tick() + { + mCallback(mMask); + // Deletes itseft after execution + return TRUE; + } + +private: + MASK mMask; + callback_t mCallback; +}; + +LLSetKeyBindDialog::LLSetKeyBindDialog(const LLSD& key) + : LLModalDialog(key), + pParent(NULL), + mKeyFilterMask(DEFAULT_KEY_FILTER), + pUpdater(NULL) +{ +} + +LLSetKeyBindDialog::~LLSetKeyBindDialog() +{ +} + +//virtual +BOOL LLSetKeyBindDialog::postBuild() +{ + childSetAction("SetEmpty", onBlank, this); + childSetAction("Default", onDefault, this); + childSetAction("Cancel", onCancel, this); + getChild<LLUICtrl>("Cancel")->setFocus(TRUE); + + pCheckBox = getChild<LLCheckBoxCtrl>("ignore_masks"); + + gFocusMgr.setKeystrokesOnly(TRUE); + + return TRUE; +} + +//virtual +void LLSetKeyBindDialog::onClose(bool app_quiting) +{ + if (pParent) + { + pParent->onCancelKeyBind(); + pParent = NULL; + } + if (pUpdater) + { + // Doubleclick timer has't fired, delete it + delete pUpdater; + pUpdater = NULL; + } + LLModalDialog::onClose(app_quiting); +} + +//virtual +void LLSetKeyBindDialog::draw() +{ + LLRect local_rect; + drawFrustum(local_rect, this, (LLView*)getDragHandle(), hasFocus()); + LLModalDialog::draw(); +} + +void LLSetKeyBindDialog::setParent(LLPanelPreferenceControls* parent, U32 key_mask) +{ + pParent = parent; + setFrustumOrigin(parent); + mKeyFilterMask = key_mask; + + LLTextBase *text_ctrl = getChild<LLTextBase>("descritption"); + + std::string input; + if ((key_mask & ALLOW_MOUSE) != 0) + { + input = getString("mouse"); + } + if ((key_mask & ALLOW_KEYS) != 0) + { + if (!input.empty()) + { + input += ", "; + } + input += getString("keyboard"); + } + text_ctrl->setTextArg("[INPUT]", input); + + bool can_ignore_masks = (key_mask & CAN_IGNORE_MASKS) != 0; + pCheckBox->setVisible(can_ignore_masks); + pCheckBox->setValue(false); +} + +BOOL LLSetKeyBindDialog::handleKeyHere(KEY key, MASK mask) +{ + if ((key == 'Q' && mask == MASK_CONTROL) + || key == KEY_ESCAPE) + { + closeFloater(); + return TRUE; + } + + if (key == KEY_DELETE) + { + setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false); + closeFloater(); + return FALSE; + } + + // forbidden keys + if (key == KEY_NONE + || key == KEY_RETURN + || key == KEY_BACKSPACE) + { + return FALSE; + } + + if ((mKeyFilterMask & ALLOW_MASKS) == 0 + && (key == KEY_CONTROL || key == KEY_SHIFT || key == KEY_ALT)) + { + // mask by themself are not allowed + return FALSE; + } + else if ((mKeyFilterMask & ALLOW_KEYS) == 0) + { + // basic keys not allowed + return FALSE; + } + else if ((mKeyFilterMask & ALLOW_MASK_KEYS) == 0 && mask != 0) + { + // masked keys not allowed + return FALSE; + } + + setKeyBind(CLICK_NONE, key, mask, pCheckBox->getValue().asBoolean()); + closeFloater(); + return TRUE; +} + +BOOL LLSetKeyBindDialog::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) +{ + BOOL result = FALSE; + if (!pParent) + { + // we already processed 'down' event, this is 'up', consume + closeFloater(); + result = TRUE; + } + if (!result && clicktype == CLICK_LEFT) + { + // try handling buttons first + if (down) + { + result = LLView::handleMouseDown(x, y, mask); + } + else + { + result = LLView::handleMouseUp(x, y, mask); + } + if (result) + { + setFocus(TRUE); + gFocusMgr.setKeystrokesOnly(TRUE); + } + // ignore selection related combinations + else if (down && (mask & (MASK_SHIFT | MASK_CONTROL)) == 0) + { + // this can be a double click, wait a bit; + if (!pUpdater) + { + // Note: default doubleclick time is 500ms, but can stretch up to 5s + pUpdater = new Updater(boost::bind(&onClickTimeout, this, _1), 0.7f, mask); + result = TRUE; + } + } + } + + if (!result + && (clicktype != CLICK_LEFT) // subcases were handled above + && ((mKeyFilterMask & ALLOW_MOUSE) != 0) + && (clicktype != CLICK_RIGHT || mask != 0) // reassigning menu button is not supported + && ((mKeyFilterMask & ALLOW_MASK_MOUSE) != 0 || mask == 0)) // reserved for selection + { + setKeyBind(clicktype, KEY_NONE, mask, pCheckBox->getValue().asBoolean()); + result = TRUE; + if (!down) + { + // wait for 'up' event before closing + // alternative: set pUpdater + closeFloater(); + } + } + + return result; +} + +//static +void LLSetKeyBindDialog::onCancel(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onBlank(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + // tmp needs 'no key' button + self->setKeyBind(CLICK_NONE, KEY_NONE, MASK_NONE, false); + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onDefault(void* user_data) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + if (self->pParent) + { + self->pParent->onDefaultKeyBind(); + self->pParent = NULL; + } + self->closeFloater(); +} + +//static +void LLSetKeyBindDialog::onClickTimeout(void* user_data, MASK mask) +{ + LLSetKeyBindDialog* self = (LLSetKeyBindDialog*)user_data; + + // timer will delete itself after timeout + self->pUpdater = NULL; + + self->setKeyBind(CLICK_LEFT, KEY_NONE, mask, self->pCheckBox->getValue().asBoolean()); + self->closeFloater(); +} + +void LLSetKeyBindDialog::setKeyBind(EMouseClickType click, KEY key, MASK mask, bool ignore) +{ + if (pParent) + { + pParent->onSetKeyBind(click, key, mask, ignore); + pParent = NULL; + } +} + |