mirror of https://github.com/stella-emu/stella.git
Fixes for various dialog boxes in 'small-window' modes.
When in TIA emulation mode at 2x zoom level, all dialogs which are variable in size will now fit in the window. In other cases, the dialog will take up 80% of the available space.
This commit is contained in:
parent
6ba627e059
commit
bab6e3119d
|
@ -29,10 +29,10 @@
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
ConfigPathDialog::ConfigPathDialog(
|
ConfigPathDialog::ConfigPathDialog(
|
||||||
OSystem& osystem, DialogContainer& parent,
|
OSystem& osystem, DialogContainer& parent,
|
||||||
const GUI::Font& font, GuiObject* boss,
|
const GUI::Font& font, GuiObject* boss)
|
||||||
int max_w, int max_h)
|
|
||||||
: Dialog(osystem, parent),
|
: Dialog(osystem, parent),
|
||||||
CommandSender(boss),
|
CommandSender(boss),
|
||||||
|
myFont(font),
|
||||||
myBrowser(nullptr),
|
myBrowser(nullptr),
|
||||||
myIsGlobal(boss != nullptr)
|
myIsGlobal(boss != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -126,9 +126,6 @@ ConfigPathDialog::ConfigPathDialog(
|
||||||
romButton->clearFlags(WIDGET_ENABLED);
|
romButton->clearFlags(WIDGET_ENABLED);
|
||||||
myRomPath->setEditable(false);
|
myRomPath->setEditable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create file browser dialog
|
|
||||||
myBrowser = make_ptr<BrowserDialog>(this, font, max_w, max_h);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -190,7 +187,7 @@ void ConfigPathDialog::setDefaults()
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void ConfigPathDialog::handleCommand(CommandSender* sender, int cmd,
|
void ConfigPathDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
int data, int id)
|
int data, int id)
|
||||||
{
|
{
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
|
@ -206,31 +203,49 @@ void ConfigPathDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kChooseRomDirCmd:
|
case kChooseRomDirCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
createBrowser();
|
||||||
myBrowser->show("Select ROM directory:", myRomPath->getText(),
|
myBrowser->show("Select ROM directory:", myRomPath->getText(),
|
||||||
BrowserDialog::Directories, LauncherDialog::kRomDirChosenCmd);
|
BrowserDialog::Directories, LauncherDialog::kRomDirChosenCmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kChooseCheatFileCmd:
|
case kChooseCheatFileCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
createBrowser();
|
||||||
myBrowser->show("Select cheat file:", myCheatFile->getText(),
|
myBrowser->show("Select cheat file:", myCheatFile->getText(),
|
||||||
BrowserDialog::FileLoad, kCheatFileChosenCmd);
|
BrowserDialog::FileLoad, kCheatFileChosenCmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kChoosePaletteFileCmd:
|
case kChoosePaletteFileCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
createBrowser();
|
||||||
myBrowser->show("Select palette file:", myPaletteFile->getText(),
|
myBrowser->show("Select palette file:", myPaletteFile->getText(),
|
||||||
BrowserDialog::FileLoad, kPaletteFileChosenCmd);
|
BrowserDialog::FileLoad, kPaletteFileChosenCmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kChoosePropsFileCmd:
|
case kChoosePropsFileCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
createBrowser();
|
||||||
myBrowser->show("Select properties file:", myPropsFile->getText(),
|
myBrowser->show("Select properties file:", myPropsFile->getText(),
|
||||||
BrowserDialog::FileLoad, kPropsFileChosenCmd);
|
BrowserDialog::FileLoad, kPropsFileChosenCmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kChooseNVRamDirCmd:
|
case kChooseNVRamDirCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
createBrowser();
|
||||||
myBrowser->show("Select NVRAM directory:", myNVRamPath->getText(),
|
myBrowser->show("Select NVRAM directory:", myNVRamPath->getText(),
|
||||||
BrowserDialog::Directories, kNVRamDirChosenCmd);
|
BrowserDialog::Directories, kNVRamDirChosenCmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kChooseStateDirCmd:
|
case kChooseStateDirCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
createBrowser();
|
||||||
myBrowser->show("Select state directory:", myStatePath->getText(),
|
myBrowser->show("Select state directory:", myStatePath->getText(),
|
||||||
BrowserDialog::Directories, kStateDirChosenCmd);
|
BrowserDialog::Directories, kStateDirChosenCmd);
|
||||||
break;
|
break;
|
||||||
|
@ -268,3 +283,15 @@ void ConfigPathDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void ConfigPathDialog::createBrowser()
|
||||||
|
{
|
||||||
|
uInt32 w = 0, h = 0;
|
||||||
|
getResizableBounds(w, h);
|
||||||
|
|
||||||
|
// Create file browser dialog
|
||||||
|
if(!myBrowser || uInt32(myBrowser->getWidth()) != w ||
|
||||||
|
uInt32(myBrowser->getHeight()) != h)
|
||||||
|
myBrowser = make_ptr<BrowserDialog>(this, myFont, w, h);
|
||||||
|
}
|
||||||
|
|
|
@ -35,12 +35,12 @@ class ConfigPathDialog : public Dialog, public CommandSender
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConfigPathDialog(OSystem& osystem, DialogContainer& parent,
|
ConfigPathDialog(OSystem& osystem, DialogContainer& parent,
|
||||||
const GUI::Font& font, GuiObject* boss,
|
const GUI::Font& font, GuiObject* boss);
|
||||||
int max_w, int max_h);
|
|
||||||
virtual ~ConfigPathDialog() = default;
|
virtual ~ConfigPathDialog() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||||
|
void createBrowser();
|
||||||
|
|
||||||
void loadConfig() override;
|
void loadConfig() override;
|
||||||
void saveConfig() override;
|
void saveConfig() override;
|
||||||
|
@ -61,7 +61,7 @@ class ConfigPathDialog : public Dialog, public CommandSender
|
||||||
kNVRamDirChosenCmd = 'LOnc' // nvram (flash/eeprom) dir changed
|
kNVRamDirChosenCmd = 'LOnc' // nvram (flash/eeprom) dir changed
|
||||||
};
|
};
|
||||||
|
|
||||||
unique_ptr<BrowserDialog> myBrowser;
|
const GUI::Font& myFont;
|
||||||
|
|
||||||
// Config paths
|
// Config paths
|
||||||
EditTextWidget* myRomPath;
|
EditTextWidget* myRomPath;
|
||||||
|
@ -71,6 +71,8 @@ class ConfigPathDialog : public Dialog, public CommandSender
|
||||||
EditTextWidget* myPaletteFile;
|
EditTextWidget* myPaletteFile;
|
||||||
EditTextWidget* myPropsFile;
|
EditTextWidget* myPropsFile;
|
||||||
|
|
||||||
|
unique_ptr<BrowserDialog> myBrowser;
|
||||||
|
|
||||||
// Indicates if this dialog is used for global (vs. in-game) settings
|
// Indicates if this dialog is used for global (vs. in-game) settings
|
||||||
bool myIsGlobal;
|
bool myIsGlobal;
|
||||||
|
|
||||||
|
|
|
@ -723,3 +723,21 @@ Widget* Dialog::TabFocus::getNewFocus()
|
||||||
|
|
||||||
return (currentTab < focus.size()) ? focus[currentTab].widget : nullptr;
|
return (currentTab < focus.size()) ? focus[currentTab].widget : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Dialog::getResizableBounds(uInt32& w, uInt32& h) const
|
||||||
|
{
|
||||||
|
const GUI::Rect& r = instance().frameBuffer().imageRect();
|
||||||
|
if(r.width() <= FrameBuffer::kFBMinW || r.height() <= FrameBuffer::kFBMinH)
|
||||||
|
{
|
||||||
|
w = uInt32(0.8 * FrameBuffer::kTIAMinW) * 2;
|
||||||
|
h = FrameBuffer::kTIAMinH * 2;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
w = std::max(uInt32(0.8 * r.width()), uInt32(FrameBuffer::kFBMinW));
|
||||||
|
h = std::max(uInt32(0.8 * r.height()), uInt32(FrameBuffer::kFBMinH));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -105,6 +105,11 @@ class Dialog : public GuiObject
|
||||||
|
|
||||||
void processCancelWithoutWidget(bool state) { _processCancel = state; }
|
void processCancelWithoutWidget(bool state) { _processCancel = state; }
|
||||||
|
|
||||||
|
/** Determine the maximum bounds based on the given width and height
|
||||||
|
Returns whether or not a large font can be used within these bounds.
|
||||||
|
*/
|
||||||
|
bool getResizableBounds(uInt32& w, uInt32& h) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void buildCurrentFocusList(int tabID = -1);
|
void buildCurrentFocusList(int tabID = -1);
|
||||||
bool handleNavEvent(Event::Type e);
|
bool handleNavEvent(Event::Type e);
|
||||||
|
|
|
@ -34,7 +34,8 @@
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
LoggerDialog::LoggerDialog(OSystem& osystem, DialogContainer& parent,
|
LoggerDialog::LoggerDialog(OSystem& osystem, DialogContainer& parent,
|
||||||
const GUI::Font& font, int max_w, int max_h)
|
const GUI::Font& font, int max_w, int max_h,
|
||||||
|
bool uselargefont)
|
||||||
: Dialog(osystem, parent),
|
: Dialog(osystem, parent),
|
||||||
myLogInfo(nullptr)
|
myLogInfo(nullptr)
|
||||||
{
|
{
|
||||||
|
@ -51,10 +52,9 @@ LoggerDialog::LoggerDialog(OSystem& osystem, DialogContainer& parent,
|
||||||
|
|
||||||
// Test listing of the log output
|
// Test listing of the log output
|
||||||
xpos = 10; ypos = 10;
|
xpos = 10; ypos = 10;
|
||||||
myLogInfo = new StringListWidget(this, instance().frameBuffer().infoFont(),
|
myLogInfo = new StringListWidget(this, uselargefont ? font :
|
||||||
xpos, ypos, _w - 2 * xpos,
|
instance().frameBuffer().infoFont(), xpos, ypos, _w - 2 * xpos,
|
||||||
_h - buttonHeight - ypos - 20 - 2 * lineHeight,
|
_h - buttonHeight - ypos - 20 - 2 * lineHeight, false);
|
||||||
false);
|
|
||||||
myLogInfo->setEditable(false);
|
myLogInfo->setEditable(false);
|
||||||
wid.push_back(myLogInfo);
|
wid.push_back(myLogInfo);
|
||||||
ypos += myLogInfo->getHeight() + 8;
|
ypos += myLogInfo->getHeight() + 8;
|
||||||
|
|
|
@ -31,7 +31,8 @@ class LoggerDialog : public Dialog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LoggerDialog(OSystem& osystem, DialogContainer& parent,
|
LoggerDialog(OSystem& osystem, DialogContainer& parent,
|
||||||
const GUI::Font& font, int max_w, int max_h);
|
const GUI::Font& font, int max_w, int max_h,
|
||||||
|
bool useLargeFont = true);
|
||||||
virtual ~LoggerDialog() = default;
|
virtual ~LoggerDialog() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -120,8 +120,8 @@ OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent,
|
||||||
myAudioDialog = make_ptr<AudioDialog>(osystem, parent, font);
|
myAudioDialog = make_ptr<AudioDialog>(osystem, parent, font);
|
||||||
myInputDialog = make_ptr<InputDialog>(osystem, parent, font, max_w, max_h);
|
myInputDialog = make_ptr<InputDialog>(osystem, parent, font, max_w, max_h);
|
||||||
myUIDialog = make_ptr<UIDialog>(osystem, parent, font);
|
myUIDialog = make_ptr<UIDialog>(osystem, parent, font);
|
||||||
mySnapshotDialog = make_ptr<SnapshotDialog>(osystem, parent, font, boss, max_w, max_h);
|
mySnapshotDialog = make_ptr<SnapshotDialog>(osystem, parent, font, boss);
|
||||||
myConfigPathDialog = make_ptr<ConfigPathDialog>(osystem, parent, font, boss, max_w, max_h);
|
myConfigPathDialog = make_ptr<ConfigPathDialog>(osystem, parent, font, boss);
|
||||||
myRomAuditDialog = make_ptr<RomAuditDialog>(osystem, parent, font, max_w, max_h);
|
myRomAuditDialog = make_ptr<RomAuditDialog>(osystem, parent, font, max_w, max_h);
|
||||||
myGameInfoDialog = make_ptr<GameInfoDialog>(osystem, parent, font, this);
|
myGameInfoDialog = make_ptr<GameInfoDialog>(osystem, parent, font, this);
|
||||||
#ifdef CHEATCODE_SUPPORT
|
#ifdef CHEATCODE_SUPPORT
|
||||||
|
@ -211,6 +211,16 @@ void OptionsDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case kLoggerCmd:
|
case kLoggerCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
if(!myIsGlobal)
|
||||||
|
{
|
||||||
|
uInt32 w = 0, h = 0;
|
||||||
|
bool uselargefont = getResizableBounds(w, h);
|
||||||
|
|
||||||
|
myLoggerDialog = make_ptr<LoggerDialog>(instance(), parent(),
|
||||||
|
instance().frameBuffer().font(), w, h, uselargefont);
|
||||||
|
}
|
||||||
myLoggerDialog->open();
|
myLoggerDialog->open();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,9 @@
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
SnapshotDialog::SnapshotDialog(
|
SnapshotDialog::SnapshotDialog(
|
||||||
OSystem& osystem, DialogContainer& parent,
|
OSystem& osystem, DialogContainer& parent,
|
||||||
const GUI::Font& font, GuiObject* boss,
|
const GUI::Font& font, GuiObject* boss)
|
||||||
int max_w, int max_h)
|
|
||||||
: Dialog(osystem, parent),
|
: Dialog(osystem, parent),
|
||||||
myBrowser(nullptr)
|
myFont(font)
|
||||||
{
|
{
|
||||||
const int lineHeight = font.getLineHeight(),
|
const int lineHeight = font.getLineHeight(),
|
||||||
fontWidth = font.getMaxCharWidth(),
|
fontWidth = font.getMaxCharWidth(),
|
||||||
|
@ -124,9 +123,6 @@ SnapshotDialog::SnapshotDialog(
|
||||||
addOKCancelBGroup(wid, font);
|
addOKCancelBGroup(wid, font);
|
||||||
|
|
||||||
addToFocusList(wid);
|
addToFocusList(wid);
|
||||||
|
|
||||||
// Create file browser dialog
|
|
||||||
myBrowser = make_ptr<BrowserDialog>(this, font, max_w, max_h);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -185,11 +181,17 @@ void SnapshotDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kChooseSnapSaveDirCmd:
|
case kChooseSnapSaveDirCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
createBrowser();
|
||||||
myBrowser->show("Select snapshot save directory:", mySnapSavePath->getText(),
|
myBrowser->show("Select snapshot save directory:", mySnapSavePath->getText(),
|
||||||
BrowserDialog::Directories, kSnapSaveDirChosenCmd);
|
BrowserDialog::Directories, kSnapSaveDirChosenCmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kChooseSnapLoadDirCmd:
|
case kChooseSnapLoadDirCmd:
|
||||||
|
// This dialog is resizable under certain conditions, so we need
|
||||||
|
// to re-create it as necessary
|
||||||
|
createBrowser();
|
||||||
myBrowser->show("Select snapshot load directory:", mySnapLoadPath->getText(),
|
myBrowser->show("Select snapshot load directory:", mySnapLoadPath->getText(),
|
||||||
BrowserDialog::Directories, kSnapLoadDirChosenCmd);
|
BrowserDialog::Directories, kSnapLoadDirChosenCmd);
|
||||||
break;
|
break;
|
||||||
|
@ -207,3 +209,15 @@ void SnapshotDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void SnapshotDialog::createBrowser()
|
||||||
|
{
|
||||||
|
uInt32 w = 0, h = 0;
|
||||||
|
getResizableBounds(w, h);
|
||||||
|
|
||||||
|
// Create file browser dialog
|
||||||
|
if(!myBrowser || uInt32(myBrowser->getWidth()) != w ||
|
||||||
|
uInt32(myBrowser->getHeight()) != h)
|
||||||
|
myBrowser = make_ptr<BrowserDialog>(this, myFont, w, h);
|
||||||
|
}
|
||||||
|
|
|
@ -35,8 +35,7 @@ class SnapshotDialog : public Dialog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SnapshotDialog(OSystem& osystem, DialogContainer& parent,
|
SnapshotDialog(OSystem& osystem, DialogContainer& parent,
|
||||||
const GUI::Font& font, GuiObject* boss,
|
const GUI::Font& font, GuiObject* boss);
|
||||||
int max_w, int max_h);
|
|
||||||
virtual ~SnapshotDialog() = default;
|
virtual ~SnapshotDialog() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -45,6 +44,7 @@ class SnapshotDialog : public Dialog
|
||||||
void setDefaults() override;
|
void setDefaults() override;
|
||||||
|
|
||||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||||
|
void createBrowser();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
|
@ -54,7 +54,7 @@ class SnapshotDialog : public Dialog
|
||||||
kSnapLoadDirChosenCmd = 'snlc' // snap chosen (load files)
|
kSnapLoadDirChosenCmd = 'snlc' // snap chosen (load files)
|
||||||
};
|
};
|
||||||
|
|
||||||
unique_ptr<BrowserDialog> myBrowser;
|
const GUI::Font& myFont;
|
||||||
|
|
||||||
// Config paths
|
// Config paths
|
||||||
EditTextWidget* mySnapSavePath;
|
EditTextWidget* mySnapSavePath;
|
||||||
|
@ -66,6 +66,8 @@ class SnapshotDialog : public Dialog
|
||||||
CheckboxWidget* mySnapSingle;
|
CheckboxWidget* mySnapSingle;
|
||||||
CheckboxWidget* mySnap1x;
|
CheckboxWidget* mySnap1x;
|
||||||
|
|
||||||
|
unique_ptr<BrowserDialog> myBrowser;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
SnapshotDialog() = delete;
|
SnapshotDialog() = delete;
|
||||||
|
|
|
@ -415,7 +415,7 @@ void UIDialog::setDefaults()
|
||||||
{
|
{
|
||||||
case 0: // Launcher options
|
case 0: // Launcher options
|
||||||
{
|
{
|
||||||
uInt32 w = std::min(instance().frameBuffer().desktopSize().w, 1000u);
|
uInt32 w = std::min(instance().frameBuffer().desktopSize().w, 900u);
|
||||||
uInt32 h = std::min(instance().frameBuffer().desktopSize().h, 600u);
|
uInt32 h = std::min(instance().frameBuffer().desktopSize().h, 600u);
|
||||||
myLauncherWidthSlider->setValue(w);
|
myLauncherWidthSlider->setValue(w);
|
||||||
myLauncherWidthLabel->setValue(w);
|
myLauncherWidthLabel->setValue(w);
|
||||||
|
|
Loading…
Reference in New Issue