mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-26 14:21:18 +00:00
ae63021d00
There were lots of places in the code that called Sys_GrabInput(), some of them each frame. Most of this is unified in events.cpp now, in handleMouseGrab() which is called once per frame by Sys_GenerateEvents() - this makes reasoning about when the mouse is grabbed and when not a lot easier. Sys_GrabInput(false) still is called in a few places, before operations that tend to take long (like loading a map or vid_restart), but (hopefully) not regularly anymore. The other big change is that the game now uses SDLs absolute mouse mode for fullscreen menus (except the PDA which is an ugly hack), so the ingame cursor is at the same position as the system cursor, which especially helps when debugging with `in_nograb 1` and should also help if someone wants to integrate an additional GUI toolkit like Dear ImGui.
4264 lines
97 KiB
C++
4264 lines
97 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "sys/platform.h"
|
|
#include "idlib/containers/HashTable.h"
|
|
#include "framework/UsercmdGen.h"
|
|
#include "framework/KeyInput.h"
|
|
#include "ui/DeviceContext.h"
|
|
#include "ui/UserInterfaceLocal.h"
|
|
#include "ui/EditWindow.h"
|
|
#include "ui/ChoiceWindow.h"
|
|
#include "ui/SliderWindow.h"
|
|
#include "ui/BindWindow.h"
|
|
#include "ui/ListWindow.h"
|
|
#include "ui/RenderWindow.h"
|
|
#include "ui/MarkerWindow.h"
|
|
#include "ui/FieldWindow.h"
|
|
#include "ui/GameSSDWindow.h"
|
|
#include "ui/GameBearShootWindow.h"
|
|
#include "ui/GameBustOutWindow.h"
|
|
// gui editor is more integrated into the window now
|
|
#include "tools/guied/GEWindowWrapper.h"
|
|
|
|
#include "ui/Window.h"
|
|
|
|
bool idWindow::registerIsTemporary[MAX_EXPRESSION_REGISTERS]; // statics to assist during parsing
|
|
//float idWindow::shaderRegisters[MAX_EXPRESSION_REGISTERS];
|
|
//wexpOp_t idWindow::shaderOps[MAX_EXPRESSION_OPS];
|
|
|
|
idCVar idWindow::gui_debug( "gui_debug", "0", CVAR_GUI | CVAR_BOOL, "" );
|
|
idCVar idWindow::gui_edit( "gui_edit", "0", CVAR_GUI | CVAR_BOOL, "" );
|
|
|
|
extern idCVar r_skipGuiShaders; // 1 = don't render any gui elements on surfaces
|
|
extern idCVar r_scaleMenusTo43;
|
|
|
|
// made RegisterVars a member of idWindow
|
|
const idRegEntry idWindow::RegisterVars[] = {
|
|
{ "forecolor", idRegister::VEC4 },
|
|
{ "hovercolor", idRegister::VEC4 },
|
|
{ "backcolor", idRegister::VEC4 },
|
|
{ "bordercolor", idRegister::VEC4 },
|
|
{ "rect", idRegister::RECTANGLE },
|
|
{ "matcolor", idRegister::VEC4 },
|
|
{ "scale", idRegister::VEC2 },
|
|
{ "translate", idRegister::VEC2 },
|
|
{ "rotate", idRegister::FLOAT },
|
|
{ "textscale", idRegister::FLOAT },
|
|
{ "visible", idRegister::BOOL },
|
|
{ "noevents", idRegister::BOOL },
|
|
{ "text", idRegister::STRING },
|
|
{ "background", idRegister::STRING },
|
|
{ "runscript", idRegister::STRING },
|
|
{ "varbackground", idRegister::STRING },
|
|
{ "cvar", idRegister::STRING },
|
|
{ "choices", idRegister::STRING },
|
|
{ "choiceVar", idRegister::STRING },
|
|
{ "bind", idRegister::STRING },
|
|
{ "modelRotate", idRegister::VEC4 },
|
|
{ "modelOrigin", idRegister::VEC4 },
|
|
{ "lightOrigin", idRegister::VEC4 },
|
|
{ "lightColor", idRegister::VEC4 },
|
|
{ "viewOffset", idRegister::VEC4 },
|
|
{ "hideCursor", idRegister::BOOL}
|
|
};
|
|
|
|
const int idWindow::NumRegisterVars = sizeof(RegisterVars) / sizeof(idRegEntry);
|
|
|
|
const char *idWindow::ScriptNames[] = {
|
|
"onMouseEnter",
|
|
"onMouseExit",
|
|
"onAction",
|
|
"onActivate",
|
|
"onDeactivate",
|
|
"onESC",
|
|
"onEvent",
|
|
"onTrigger",
|
|
"onActionRelease",
|
|
"onEnter",
|
|
"onEnterRelease"
|
|
};
|
|
|
|
/*
|
|
================
|
|
idWindow::CommonInit
|
|
================
|
|
*/
|
|
void idWindow::CommonInit() {
|
|
childID = 0;
|
|
flags = 0;
|
|
lastTimeRun = 0;
|
|
origin.Zero();
|
|
fontNum = 0;
|
|
timeLine = -1;
|
|
xOffset = yOffset = 0.0;
|
|
cursor = 0;
|
|
forceAspectWidth = 640;
|
|
forceAspectHeight = 480;
|
|
matScalex = 1;
|
|
matScaley = 1;
|
|
borderSize = 0;
|
|
noTime = false;
|
|
visible = true;
|
|
textAlign = 0;
|
|
textAlignx = 0;
|
|
textAligny = 0;
|
|
noEvents = false;
|
|
rotate = 0;
|
|
shear.Zero();
|
|
textScale = 0.35f;
|
|
backColor.Zero();
|
|
foreColor = idVec4(1, 1, 1, 1);
|
|
hoverColor = idVec4(1, 1, 1, 1);
|
|
matColor = idVec4(1, 1, 1, 1);
|
|
borderColor.Zero();
|
|
background = NULL;
|
|
backGroundName = "";
|
|
focusedChild = NULL;
|
|
captureChild = NULL;
|
|
overChild = NULL;
|
|
parent = NULL;
|
|
saveOps = NULL;
|
|
saveRegs = NULL;
|
|
timeLine = -1;
|
|
textShadow = 0;
|
|
hover = false;
|
|
|
|
for (int i = 0; i < SCRIPT_COUNT; i++) {
|
|
scripts[i] = NULL;
|
|
}
|
|
|
|
hideCursor = false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Size
|
|
================
|
|
*/
|
|
size_t idWindow::Size() {
|
|
int c = children.Num();
|
|
int sz = 0;
|
|
for (int i = 0; i < c; i++) {
|
|
sz += children[i]->Size();
|
|
}
|
|
sz += sizeof(*this) + Allocated();
|
|
return sz;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Allocated
|
|
================
|
|
*/
|
|
size_t idWindow::Allocated() {
|
|
int i, c;
|
|
int sz = name.Allocated();
|
|
sz += text.Size();
|
|
sz += backGroundName.Size();
|
|
|
|
c = definedVars.Num();
|
|
for (i = 0; i < c; i++) {
|
|
sz += definedVars[i]->Size();
|
|
}
|
|
|
|
for (i = 0; i < SCRIPT_COUNT; i++) {
|
|
if (scripts[i]) {
|
|
sz += scripts[i]->Size();
|
|
}
|
|
}
|
|
c = timeLineEvents.Num();
|
|
for (i = 0; i < c; i++) {
|
|
sz += timeLineEvents[i]->Size();
|
|
}
|
|
|
|
c = namedEvents.Num();
|
|
for (i = 0; i < c; i++) {
|
|
sz += namedEvents[i]->Size();
|
|
}
|
|
|
|
c = drawWindows.Num();
|
|
for (i = 0; i < c; i++) {
|
|
if (drawWindows[i].simp) {
|
|
sz += drawWindows[i].simp->Size();
|
|
}
|
|
}
|
|
|
|
return sz;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::idWindow
|
|
================
|
|
*/
|
|
idWindow::idWindow(idUserInterfaceLocal *ui) {
|
|
dc = NULL;
|
|
gui = ui;
|
|
CommonInit();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::idWindow
|
|
================
|
|
*/
|
|
idWindow::idWindow(idDeviceContext *d, idUserInterfaceLocal *ui) {
|
|
dc = d;
|
|
gui = ui;
|
|
CommonInit();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::CleanUp
|
|
================
|
|
*/
|
|
void idWindow::CleanUp() {
|
|
int i, c = drawWindows.Num();
|
|
for (i = 0; i < c; i++) {
|
|
delete drawWindows[i].simp;
|
|
}
|
|
|
|
// ensure the register list gets cleaned up
|
|
regList.Reset ( );
|
|
|
|
// Cleanup the named events
|
|
namedEvents.DeleteContents(true);
|
|
|
|
// Cleanup the operations and update vars
|
|
// (if it is not fixed, orphane register references are possible)
|
|
ops.Clear();
|
|
updateVars.Clear();
|
|
|
|
drawWindows.Clear();
|
|
children.DeleteContents(true);
|
|
definedVars.DeleteContents(true);
|
|
timeLineEvents.DeleteContents(true);
|
|
for (i = 0; i < SCRIPT_COUNT; i++) {
|
|
delete scripts[i];
|
|
}
|
|
CommonInit();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::~idWindow
|
|
================
|
|
*/
|
|
idWindow::~idWindow() {
|
|
CleanUp();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Move
|
|
================
|
|
*/
|
|
void idWindow::Move(float x, float y) {
|
|
idRectangle rct = rect;
|
|
rct.x = x;
|
|
rct.y = y;
|
|
idRegister *reg = RegList()->FindReg("rect");
|
|
if (reg) {
|
|
reg->Enable(false);
|
|
}
|
|
rect = rct;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetFont
|
|
================
|
|
*/
|
|
void idWindow::SetFont() {
|
|
dc->SetFont(fontNum);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetMaxCharHeight
|
|
================
|
|
*/
|
|
float idWindow::GetMaxCharHeight() {
|
|
SetFont();
|
|
return dc->MaxCharHeight(textScale);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetMaxCharWidth
|
|
================
|
|
*/
|
|
float idWindow::GetMaxCharWidth() {
|
|
SetFont();
|
|
return dc->MaxCharWidth(textScale);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Draw
|
|
================
|
|
*/
|
|
void idWindow::Draw( int time, float x, float y ) {
|
|
if ( text.Length() == 0 ) {
|
|
return;
|
|
}
|
|
if ( textShadow ) {
|
|
idStr shadowText = text;
|
|
idRectangle shadowRect = textRect;
|
|
|
|
shadowText.RemoveColors();
|
|
shadowRect.x += textShadow;
|
|
shadowRect.y += textShadow;
|
|
|
|
dc->DrawText( shadowText, textScale, textAlign, colorBlack, shadowRect, !( flags & WIN_NOWRAP ), -1 );
|
|
}
|
|
dc->DrawText( text, textScale, textAlign, foreColor, textRect, !( flags & WIN_NOWRAP ), -1 );
|
|
|
|
if ( gui_edit.GetBool() ) {
|
|
dc->EnableClipping( false );
|
|
dc->DrawText( va( "x: %i y: %i", ( int )rect.x(), ( int )rect.y() ), 0.25, 0, dc->colorWhite, idRectangle( rect.x(), rect.y() - 15, 100, 20 ), false );
|
|
dc->DrawText( va( "w: %i h: %i", ( int )rect.w(), ( int )rect.h() ), 0.25, 0, dc->colorWhite, idRectangle( rect.x() + rect.w(), rect.w() + rect.h() + 5, 100, 20 ), false );
|
|
dc->EnableClipping( true );
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::BringToTop
|
|
================
|
|
*/
|
|
void idWindow::BringToTop(idWindow *w) {
|
|
|
|
if (w && !(w->flags & WIN_MODAL)) {
|
|
return;
|
|
}
|
|
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if (children[i] == w) {
|
|
// this is it move from i - 1 to 0 to i to 1 then shove this one into 0
|
|
for (int j = i+1; j < c; j++) {
|
|
children[j-1] = children[j];
|
|
}
|
|
children[c-1] = w;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Size
|
|
================
|
|
*/
|
|
void idWindow::Size(float x, float y, float w, float h) {
|
|
idRectangle rct = rect;
|
|
rct.x = x;
|
|
rct.y = y;
|
|
rct.w = w;
|
|
rct.h = h;
|
|
rect = rct;
|
|
CalcClientRect(0,0);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::MouseEnter
|
|
================
|
|
*/
|
|
void idWindow::MouseEnter() {
|
|
|
|
if (noEvents) {
|
|
return;
|
|
}
|
|
|
|
RunScript(ON_MOUSEENTER);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::MouseExit
|
|
================
|
|
*/
|
|
void idWindow::MouseExit() {
|
|
|
|
if (noEvents) {
|
|
return;
|
|
}
|
|
|
|
RunScript(ON_MOUSEEXIT);
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
idWindow::RouteMouseCoords
|
|
================
|
|
*/
|
|
const char *idWindow::RouteMouseCoords(float xd, float yd) {
|
|
idStr str;
|
|
if (GetCaptureChild()) {
|
|
//FIXME: unkludge this whole mechanism
|
|
return GetCaptureChild()->RouteMouseCoords(xd, yd);
|
|
}
|
|
|
|
if (xd == -2000 || yd == -2000) {
|
|
return "";
|
|
}
|
|
|
|
int c = children.Num();
|
|
while (c > 0) {
|
|
idWindow *child = children[--c];
|
|
if (child->visible && !child->noEvents && child->Contains(child->drawRect, gui->CursorX(), gui->CursorY())) {
|
|
|
|
dc->SetCursor(child->cursor);
|
|
child->hover = true;
|
|
|
|
if (overChild != child) {
|
|
if (overChild) {
|
|
overChild->MouseExit();
|
|
str = overChild->cmd;
|
|
if (str.Length()) {
|
|
gui->GetDesktop()->AddCommand(str);
|
|
overChild->cmd = "";
|
|
}
|
|
}
|
|
overChild = child;
|
|
overChild->MouseEnter();
|
|
str = overChild->cmd;
|
|
if (str.Length()) {
|
|
gui->GetDesktop()->AddCommand(str);
|
|
overChild->cmd = "";
|
|
}
|
|
} else {
|
|
if (!(child->flags & WIN_HOLDCAPTURE)) {
|
|
child->RouteMouseCoords(xd, yd);
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
}
|
|
if (overChild) {
|
|
overChild->MouseExit();
|
|
str = overChild->cmd;
|
|
if (str.Length()) {
|
|
gui->GetDesktop()->AddCommand(str);
|
|
overChild->cmd = "";
|
|
}
|
|
overChild = NULL;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Activate
|
|
================
|
|
*/
|
|
void idWindow::Activate( bool activate, idStr &act ) {
|
|
|
|
int n = (activate) ? ON_ACTIVATE : ON_DEACTIVATE;
|
|
|
|
// make sure win vars are updated before activation
|
|
UpdateWinVars ( );
|
|
|
|
RunScript(n);
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
children[i]->Activate( activate, act );
|
|
}
|
|
|
|
if ( act.Length() ) {
|
|
act += " ; ";
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Trigger
|
|
================
|
|
*/
|
|
void idWindow::Trigger() {
|
|
RunScript( ON_TRIGGER );
|
|
int c = children.Num();
|
|
for ( int i = 0; i < c; i++ ) {
|
|
children[i]->Trigger();
|
|
}
|
|
StateChanged( true );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::StateChanged
|
|
================
|
|
*/
|
|
void idWindow::StateChanged( bool redraw ) {
|
|
|
|
UpdateWinVars();
|
|
|
|
if (expressionRegisters.Num() && ops.Num()) {
|
|
EvalRegs();
|
|
}
|
|
|
|
int c = drawWindows.Num();
|
|
for ( int i = 0; i < c; i++ ) {
|
|
if ( drawWindows[i].win ) {
|
|
drawWindows[i].win->StateChanged( redraw );
|
|
} else {
|
|
drawWindows[i].simp->StateChanged( redraw );
|
|
}
|
|
}
|
|
|
|
if ( redraw ) {
|
|
if ( flags & WIN_DESKTOP ) {
|
|
Redraw( 0.0f, 0.0f );
|
|
}
|
|
if ( background && background->CinematicLength() ) {
|
|
background->UpdateCinematic( gui->GetTime() );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetCapture
|
|
================
|
|
*/
|
|
idWindow *idWindow::SetCapture(idWindow *w) {
|
|
// only one child can have the focus
|
|
|
|
idWindow *last = NULL;
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if ( children[i]->flags & WIN_CAPTURE ) {
|
|
last = children[i];
|
|
//last->flags &= ~WIN_CAPTURE;
|
|
last->LoseCapture();
|
|
break;
|
|
}
|
|
}
|
|
|
|
w->flags |= WIN_CAPTURE;
|
|
w->GainCapture();
|
|
gui->GetDesktop()->captureChild = w;
|
|
return last;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::AddUpdateVar
|
|
================
|
|
*/
|
|
void idWindow::AddUpdateVar(idWinVar *var) {
|
|
updateVars.AddUnique(var);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::UpdateWinVars
|
|
================
|
|
*/
|
|
void idWindow::UpdateWinVars() {
|
|
int c = updateVars.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
updateVars[i]->Update();
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::RunTimeEvents
|
|
================
|
|
*/
|
|
bool idWindow::RunTimeEvents(int time) {
|
|
|
|
if ( time - lastTimeRun < USERCMD_MSEC ) {
|
|
//common->Printf("Skipping gui time events at %i\n", time);
|
|
return false;
|
|
}
|
|
|
|
lastTimeRun = time;
|
|
|
|
UpdateWinVars();
|
|
|
|
if (expressionRegisters.Num() && ops.Num()) {
|
|
EvalRegs();
|
|
}
|
|
|
|
if ( flags & WIN_INTRANSITION ) {
|
|
Transition();
|
|
}
|
|
|
|
Time();
|
|
|
|
// renamed ON_EVENT to ON_FRAME
|
|
RunScript(ON_FRAME);
|
|
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
children[i]->RunTimeEvents(time);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::RunNamedEvent
|
|
================
|
|
*/
|
|
void idWindow::RunNamedEvent ( const char* eventName )
|
|
{
|
|
int i;
|
|
int c;
|
|
|
|
// Find and run the event
|
|
c = namedEvents.Num( );
|
|
for ( i = 0; i < c; i ++ ) {
|
|
if ( namedEvents[i]->mName.Icmp( eventName ) ) {
|
|
continue;
|
|
}
|
|
|
|
UpdateWinVars();
|
|
|
|
// Make sure we got all the current values for stuff
|
|
if (expressionRegisters.Num() && ops.Num()) {
|
|
EvalRegs(-1, true);
|
|
}
|
|
|
|
RunScriptList( namedEvents[i]->mEvent );
|
|
|
|
break;
|
|
}
|
|
|
|
// Run the event in all the children as well
|
|
c = children.Num();
|
|
for ( i = 0; i < c; i++ ) {
|
|
children[i]->RunNamedEvent ( eventName );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Contains
|
|
================
|
|
*/
|
|
bool idWindow::Contains(const idRectangle &sr, float x, float y) {
|
|
idRectangle r = sr;
|
|
r.x += actualX - drawRect.x;
|
|
r.y += actualY - drawRect.y;
|
|
return r.Contains(x, y);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Contains
|
|
================
|
|
*/
|
|
bool idWindow::Contains(float x, float y) {
|
|
idRectangle r = drawRect;
|
|
r.x = actualX;
|
|
r.y = actualY;
|
|
return r.Contains(x, y);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::AddCommand
|
|
================
|
|
*/
|
|
void idWindow::AddCommand(const char *_cmd) {
|
|
idStr str = cmd;
|
|
if (str.Length()) {
|
|
str += " ; ";
|
|
str += _cmd;
|
|
} else {
|
|
str = _cmd;
|
|
}
|
|
cmd = str;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::HandleEvent
|
|
================
|
|
*/
|
|
const char *idWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) {
|
|
static bool actionDownRun;
|
|
static bool actionUpRun;
|
|
|
|
cmd = "";
|
|
|
|
if ( flags & WIN_DESKTOP ) {
|
|
actionDownRun = false;
|
|
actionUpRun = false;
|
|
if (expressionRegisters.Num() && ops.Num()) {
|
|
EvalRegs();
|
|
}
|
|
RunTimeEvents(gui->GetTime());
|
|
CalcRects(0,0);
|
|
dc->SetCursor( idDeviceContext::CURSOR_ARROW );
|
|
}
|
|
|
|
if (visible && !noEvents) {
|
|
|
|
if (event->evType == SE_KEY) {
|
|
EvalRegs(-1, true);
|
|
if (updateVisuals) {
|
|
*updateVisuals = true;
|
|
}
|
|
|
|
if (event->evValue == K_MOUSE1) {
|
|
|
|
if (!event->evValue2 && GetCaptureChild()) {
|
|
GetCaptureChild()->LoseCapture();
|
|
gui->GetDesktop()->captureChild = NULL;
|
|
return "";
|
|
}
|
|
|
|
int c = children.Num();
|
|
while (--c >= 0) {
|
|
if (children[c]->visible && children[c]->Contains(children[c]->drawRect, gui->CursorX(), gui->CursorY()) && !(children[c]->noEvents)) {
|
|
idWindow *child = children[c];
|
|
if (event->evValue2) {
|
|
BringToTop(child);
|
|
SetFocus(child);
|
|
if (child->flags & WIN_HOLDCAPTURE) {
|
|
SetCapture(child);
|
|
}
|
|
}
|
|
if (child->Contains(child->clientRect, gui->CursorX(), gui->CursorY())) {
|
|
//if ((gui_edit.GetBool() && (child->flags & WIN_SELECTED)) || (!gui_edit.GetBool() && (child->flags & WIN_MOVABLE))) {
|
|
// SetCapture(child);
|
|
//}
|
|
SetFocus(child);
|
|
const char *childRet = child->HandleEvent(event, updateVisuals);
|
|
if (childRet && *childRet) {
|
|
return childRet;
|
|
}
|
|
if (child->flags & WIN_MODAL) {
|
|
return "";
|
|
}
|
|
} else {
|
|
if (event->evValue2) {
|
|
SetFocus(child);
|
|
bool capture = true;
|
|
if (capture && ((child->flags & WIN_MOVABLE) || gui_edit.GetBool())) {
|
|
SetCapture(child);
|
|
}
|
|
return "";
|
|
} else {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (event->evValue2 && !actionDownRun) {
|
|
actionDownRun = RunScript( ON_ACTION );
|
|
} else if (!actionUpRun) {
|
|
actionUpRun = RunScript( ON_ACTIONRELEASE );
|
|
}
|
|
} else if (event->evValue == K_MOUSE2) {
|
|
|
|
if (!event->evValue2 && GetCaptureChild()) {
|
|
GetCaptureChild()->LoseCapture();
|
|
gui->GetDesktop()->captureChild = NULL;
|
|
return "";
|
|
}
|
|
|
|
int c = children.Num();
|
|
while (--c >= 0) {
|
|
if (children[c]->visible && children[c]->Contains(children[c]->drawRect, gui->CursorX(), gui->CursorY()) && !(children[c]->noEvents)) {
|
|
idWindow *child = children[c];
|
|
if (event->evValue2) {
|
|
BringToTop(child);
|
|
SetFocus(child);
|
|
}
|
|
if (child->Contains(child->clientRect,gui->CursorX(), gui->CursorY()) || GetCaptureChild() == child) {
|
|
if ((gui_edit.GetBool() && (child->flags & WIN_SELECTED)) || (!gui_edit.GetBool() && (child->flags & WIN_MOVABLE))) {
|
|
SetCapture(child);
|
|
}
|
|
const char *childRet = child->HandleEvent(event, updateVisuals);
|
|
if (childRet && *childRet) {
|
|
return childRet;
|
|
}
|
|
if (child->flags & WIN_MODAL) {
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (event->evValue == K_MOUSE3) {
|
|
if (gui_edit.GetBool()) {
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if (children[i]->drawRect.Contains(gui->CursorX(), gui->CursorY())) {
|
|
if (event->evValue2) {
|
|
children[i]->flags ^= WIN_SELECTED;
|
|
if (children[i]->flags & WIN_SELECTED) {
|
|
flags &= ~WIN_SELECTED;
|
|
return "childsel";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (event->evValue == K_TAB && event->evValue2) {
|
|
if (GetFocusedChild()) {
|
|
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
|
|
if (childRet && *childRet) {
|
|
return childRet;
|
|
}
|
|
|
|
// If the window didn't handle the tab, then move the focus to the next window
|
|
// or the previous window if shift is held down
|
|
|
|
int direction = 1;
|
|
if ( idKeyInput::IsDown( K_SHIFT ) ) {
|
|
direction = -1;
|
|
}
|
|
|
|
idWindow *currentFocus = GetFocusedChild();
|
|
idWindow *child = GetFocusedChild();
|
|
idWindow *parent = child->GetParent();
|
|
while ( parent ) {
|
|
bool foundFocus = false;
|
|
bool recurse = false;
|
|
int index = 0;
|
|
if ( child ) {
|
|
index = parent->GetChildIndex( child ) + direction;
|
|
} else if ( direction < 0 ) {
|
|
index = parent->GetChildCount() - 1;
|
|
}
|
|
while ( index < parent->GetChildCount() && index >= 0) {
|
|
idWindow *testWindow = parent->GetChild( index );
|
|
if ( testWindow == currentFocus ) {
|
|
// we managed to wrap around and get back to our starting window
|
|
foundFocus = true;
|
|
break;
|
|
}
|
|
if ( testWindow && !testWindow->noEvents && testWindow->visible ) {
|
|
if ( testWindow->flags & WIN_CANFOCUS ) {
|
|
SetFocus( testWindow );
|
|
foundFocus = true;
|
|
break;
|
|
} else if ( testWindow->GetChildCount() > 0 ) {
|
|
parent = testWindow;
|
|
child = NULL;
|
|
recurse = true;
|
|
break;
|
|
}
|
|
}
|
|
index += direction;
|
|
}
|
|
if ( foundFocus ) {
|
|
// We found a child to focus on
|
|
break;
|
|
} else if ( recurse ) {
|
|
// We found a child with children
|
|
continue;
|
|
} else {
|
|
// We didn't find anything, so go back up to our parent
|
|
child = parent;
|
|
parent = child->GetParent();
|
|
if ( parent == gui->GetDesktop() ) {
|
|
// We got back to the desktop, so wrap around but don't actually go to the desktop
|
|
parent = NULL;
|
|
child = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (event->evValue == K_ESCAPE && event->evValue2) {
|
|
if (GetFocusedChild()) {
|
|
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
|
|
if (childRet && *childRet) {
|
|
return childRet;
|
|
}
|
|
}
|
|
RunScript( ON_ESC );
|
|
} else if (event->evValue == K_ENTER ) {
|
|
if (GetFocusedChild()) {
|
|
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
|
|
if (childRet && *childRet) {
|
|
return childRet;
|
|
}
|
|
}
|
|
if ( flags & WIN_WANTENTER ) {
|
|
if ( event->evValue2 ) {
|
|
RunScript( ON_ACTION );
|
|
} else {
|
|
RunScript( ON_ACTIONRELEASE );
|
|
}
|
|
}
|
|
} else {
|
|
if (GetFocusedChild()) {
|
|
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
|
|
if (childRet && *childRet) {
|
|
return childRet;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if (event->evType == SE_MOUSE || event->evType == SE_MOUSE_ABS) {
|
|
if (updateVisuals) {
|
|
*updateVisuals = true;
|
|
}
|
|
const char *mouseRet = RouteMouseCoords(event->evValue, event->evValue2);
|
|
if (mouseRet && *mouseRet) {
|
|
return mouseRet;
|
|
}
|
|
} else if (event->evType == SE_NONE) {
|
|
} else if (event->evType == SE_CHAR) {
|
|
if (GetFocusedChild()) {
|
|
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
|
|
if (childRet && *childRet) {
|
|
return childRet;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gui->GetReturnCmd() = cmd;
|
|
if ( gui->GetPendingCmd().Length() ) {
|
|
gui->GetReturnCmd() += " ; ";
|
|
gui->GetReturnCmd() += gui->GetPendingCmd();
|
|
gui->GetPendingCmd().Clear();
|
|
}
|
|
cmd = "";
|
|
return gui->GetReturnCmd();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::DebugDraw
|
|
================
|
|
*/
|
|
void idWindow::DebugDraw(int time, float x, float y) {
|
|
static char buff[16384];
|
|
if (dc) {
|
|
dc->EnableClipping(false);
|
|
if (gui_debug.GetInteger() == 1) {
|
|
dc->DrawRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, 1, idDeviceContext::colorRed);
|
|
} else if (gui_debug.GetInteger() == 2) {
|
|
char out[1024];
|
|
idStr str;
|
|
str = text.c_str();
|
|
|
|
if (str.Length()) {
|
|
sprintf(buff, "%s\n", str.c_str());
|
|
}
|
|
|
|
sprintf(out, "Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", rect.x(), rect.y(), rect.w(), rect.h());
|
|
strcat(buff, out);
|
|
sprintf(out, "Draw Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", drawRect.x, drawRect.y, drawRect.w, drawRect.h);
|
|
strcat(buff, out);
|
|
sprintf(out, "Client Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", clientRect.x, clientRect.y, clientRect.w, clientRect.h);
|
|
strcat(buff, out);
|
|
sprintf(out, "Cursor: %0.1f : %0.1f\n", gui->CursorX(), gui->CursorY());
|
|
strcat(buff, out);
|
|
|
|
|
|
//idRectangle tempRect = textRect;
|
|
//tempRect.x += offsetX;
|
|
//drawRect.y += offsetY;
|
|
dc->DrawText(buff, textScale, textAlign, foreColor, textRect, true);
|
|
}
|
|
dc->EnableClipping(true);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Transition
|
|
================
|
|
*/
|
|
void idWindow::Transition() {
|
|
int i, c = transitions.Num();
|
|
bool clear = true;
|
|
|
|
for ( i = 0; i < c; i++ ) {
|
|
idTransitionData *data = &transitions[i];
|
|
idWinRectangle *r = NULL;
|
|
idWinVec4 *v4 = dynamic_cast<idWinVec4*>(data->data);
|
|
idWinFloat* val = NULL;
|
|
if (v4 == NULL) {
|
|
r = dynamic_cast<idWinRectangle*>(data->data);
|
|
if ( !r ) {
|
|
val = dynamic_cast<idWinFloat*>(data->data);
|
|
}
|
|
}
|
|
if ( data->interp.IsDone( gui->GetTime() ) && data->data) {
|
|
if (v4) {
|
|
*v4 = data->interp.GetEndValue();
|
|
} else if ( val ) {
|
|
*val = data->interp.GetEndValue()[0];
|
|
} else {
|
|
*r = data->interp.GetEndValue();
|
|
}
|
|
} else {
|
|
clear = false;
|
|
if (data->data) {
|
|
if (v4) {
|
|
*v4 = data->interp.GetCurrentValue( gui->GetTime() );
|
|
} else if ( val ) {
|
|
*val = data->interp.GetCurrentValue( gui->GetTime() )[0];
|
|
} else {
|
|
*r = data->interp.GetCurrentValue( gui->GetTime() );
|
|
}
|
|
} else {
|
|
common->Warning("Invalid transitional data for window %s in gui %s", GetName(), gui->GetSourceFile());
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( clear ) {
|
|
transitions.SetNum( 0, false );
|
|
flags &= ~WIN_INTRANSITION;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Time
|
|
================
|
|
*/
|
|
void idWindow::Time() {
|
|
|
|
if ( noTime ) {
|
|
return;
|
|
}
|
|
|
|
if ( timeLine == -1 ) {
|
|
timeLine = gui->GetTime();
|
|
}
|
|
|
|
cmd = "";
|
|
|
|
int c = timeLineEvents.Num();
|
|
if ( c > 0 ) {
|
|
for (int i = 0; i < c; i++) {
|
|
if ( timeLineEvents[i]->pending && gui->GetTime() - timeLine >= timeLineEvents[i]->time ) {
|
|
timeLineEvents[i]->pending = false;
|
|
RunScriptList( timeLineEvents[i]->event );
|
|
}
|
|
}
|
|
}
|
|
if ( gui->Active() ) {
|
|
gui->GetPendingCmd() += cmd;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::EvalRegs
|
|
================
|
|
*/
|
|
float idWindow::EvalRegs(int test, bool force) {
|
|
static float regs[MAX_EXPRESSION_REGISTERS];
|
|
static idWindow *lastEval = NULL;
|
|
|
|
if (!force && test >= 0 && test < MAX_EXPRESSION_REGISTERS && lastEval == this) {
|
|
return regs[test];
|
|
}
|
|
|
|
lastEval = this;
|
|
|
|
if (expressionRegisters.Num()) {
|
|
regList.SetToRegs(regs);
|
|
EvaluateRegisters(regs);
|
|
regList.GetFromRegs(regs);
|
|
}
|
|
|
|
if (test >= 0 && test < MAX_EXPRESSION_REGISTERS) {
|
|
return regs[test];
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::DrawBackground
|
|
================
|
|
*/
|
|
void idWindow::DrawBackground(const idRectangle &drawRect) {
|
|
if ( backColor.w() ) {
|
|
dc->DrawFilledRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, backColor);
|
|
}
|
|
|
|
if ( background && matColor.w() ) {
|
|
float scalex, scaley;
|
|
if ( flags & WIN_NATURALMAT ) {
|
|
scalex = drawRect.w / background->GetImageWidth();
|
|
scaley = drawRect.h / background->GetImageHeight();
|
|
} else {
|
|
scalex = matScalex;
|
|
scaley = matScaley;
|
|
}
|
|
dc->DrawMaterial(drawRect.x, drawRect.y, drawRect.w, drawRect.h, background, matColor, scalex, scaley);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::DrawBorderAndCaption
|
|
================
|
|
*/
|
|
void idWindow::DrawBorderAndCaption(const idRectangle &drawRect) {
|
|
if ( flags & WIN_BORDER && borderSize && borderColor.w() ) {
|
|
dc->DrawRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, borderSize, borderColor);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetupTransforms
|
|
================
|
|
*/
|
|
void idWindow::SetupTransforms(float x, float y) {
|
|
static idMat3 trans;
|
|
static idVec3 org;
|
|
|
|
trans.Identity();
|
|
org.Set( origin.x + x, origin.y + y, 0 );
|
|
|
|
if ( rotate ) {
|
|
static idRotation rot;
|
|
static idVec3 vec(0, 0, 1);
|
|
rot.Set( org, vec, rotate );
|
|
trans = rot.ToMat3();
|
|
}
|
|
|
|
if ( shear.x || shear.y ) {
|
|
static idMat3 smat;
|
|
smat.Identity();
|
|
smat[0][1] = shear.x;
|
|
smat[1][0] = shear.y;
|
|
trans *= smat;
|
|
}
|
|
|
|
if ( !trans.IsIdentity() ) {
|
|
dc->SetTransformInfo( org, trans );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::CalcRects
|
|
================
|
|
*/
|
|
void idWindow::CalcRects(float x, float y) {
|
|
CalcClientRect(0, 0);
|
|
drawRect.Offset(x, y);
|
|
clientRect.Offset(x, y);
|
|
actualX = drawRect.x;
|
|
actualY = drawRect.y;
|
|
int c = drawWindows.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if (drawWindows[i].win) {
|
|
drawWindows[i].win->CalcRects(clientRect.x + xOffset, clientRect.y + yOffset);
|
|
}
|
|
}
|
|
drawRect.Offset(-x, -y);
|
|
clientRect.Offset(-x, -y);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Redraw
|
|
================
|
|
*/
|
|
void idWindow::Redraw(float x, float y) {
|
|
idStr str;
|
|
|
|
if (r_skipGuiShaders.GetInteger() == 1 || dc == NULL ) {
|
|
return;
|
|
}
|
|
|
|
int time = gui->GetTime();
|
|
|
|
if ( flags & WIN_DESKTOP && r_skipGuiShaders.GetInteger() != 3 ) {
|
|
RunTimeEvents( time );
|
|
}
|
|
|
|
if ( r_skipGuiShaders.GetInteger() == 2 ) {
|
|
return;
|
|
}
|
|
|
|
// DG: allow scaling menus to 4:3
|
|
bool fixupFor43 = false;
|
|
if ( flags & WIN_DESKTOP ) {
|
|
// only scale desktop windows (will automatically scale its sub-windows)
|
|
// that EITHER have the scaleto43 flag set OR are fullscreen menus and r_scaleMenusTo43 is 1
|
|
if( (flags & WIN_SCALETO43) ||
|
|
((flags & WIN_MENUGUI) && r_scaleMenusTo43.GetBool()) )
|
|
{
|
|
fixupFor43 = true;
|
|
dc->SetMenuScaleFix(true);
|
|
}
|
|
}
|
|
|
|
if ( flags & WIN_SHOWTIME ) {
|
|
dc->DrawText(va(" %0.1f seconds\n%s", (float)(time - timeLine) / 1000, gui->State().GetString("name")), 0.35f, 0, dc->colorWhite, idRectangle(100, 0, 80, 80), false);
|
|
}
|
|
|
|
if ( flags & WIN_SHOWCOORDS ) {
|
|
dc->EnableClipping(false);
|
|
sprintf(str, "x: %i y: %i cursorx: %i cursory: %i", (int)rect.x(), (int)rect.y(), (int)gui->CursorX(), (int)gui->CursorY());
|
|
dc->DrawText(str, 0.25f, 0, dc->colorWhite, idRectangle(0, 0, 100, 20), false);
|
|
dc->EnableClipping(true);
|
|
}
|
|
|
|
if (!visible) {
|
|
if (fixupFor43) { // DG: gotta reset that before returning this function
|
|
dc->SetMenuScaleFix(false);
|
|
}
|
|
return;
|
|
}
|
|
|
|
CalcClientRect(0, 0);
|
|
|
|
SetFont();
|
|
//if (flags & WIN_DESKTOP) {
|
|
// see if this window forces a new aspect ratio
|
|
dc->SetSize(forceAspectWidth, forceAspectHeight);
|
|
//}
|
|
|
|
//FIXME: go to screen coord tracking
|
|
drawRect.Offset(x, y);
|
|
clientRect.Offset(x, y);
|
|
textRect.Offset(x, y);
|
|
actualX = drawRect.x;
|
|
actualY = drawRect.y;
|
|
|
|
idVec3 oldOrg;
|
|
idMat3 oldTrans;
|
|
|
|
dc->GetTransformInfo( oldOrg, oldTrans );
|
|
|
|
SetupTransforms(x, y);
|
|
DrawBackground(drawRect);
|
|
DrawBorderAndCaption(drawRect);
|
|
|
|
if ( !( flags & WIN_NOCLIP) ) {
|
|
dc->PushClipRect(clientRect);
|
|
}
|
|
|
|
if ( r_skipGuiShaders.GetInteger() < 5 ) {
|
|
Draw(time, x, y);
|
|
}
|
|
|
|
if ( gui_debug.GetInteger() ) {
|
|
DebugDraw(time, x, y);
|
|
}
|
|
|
|
int c = drawWindows.Num();
|
|
for ( int i = 0; i < c; i++ ) {
|
|
if ( drawWindows[i].win ) {
|
|
drawWindows[i].win->Redraw( clientRect.x + xOffset, clientRect.y + yOffset );
|
|
} else {
|
|
drawWindows[i].simp->Redraw( clientRect.x + xOffset, clientRect.y + yOffset );
|
|
}
|
|
}
|
|
|
|
// Put transforms back to what they were before the children were processed
|
|
dc->SetTransformInfo(oldOrg, oldTrans);
|
|
|
|
if ( ! ( flags & WIN_NOCLIP ) ) {
|
|
dc->PopClipRect();
|
|
}
|
|
|
|
if (gui_edit.GetBool() || (flags & WIN_DESKTOP && !( flags & WIN_NOCURSOR ) && !hideCursor && (gui->Active() || ( flags & WIN_MENUGUI ) ))) {
|
|
dc->SetTransformInfo(vec3_origin, mat3_identity);
|
|
gui->DrawCursor();
|
|
}
|
|
|
|
if (gui_debug.GetInteger() && flags & WIN_DESKTOP) {
|
|
dc->EnableClipping(false);
|
|
sprintf(str, "x: %1.f y: %1.f", gui->CursorX(), gui->CursorY());
|
|
dc->DrawText(str, 0.25, 0, dc->colorWhite, idRectangle(0, 0, 100, 20), false);
|
|
dc->DrawText(gui->GetSourceFile(), 0.25, 0, dc->colorWhite, idRectangle(0, 20, 300, 20), false);
|
|
dc->EnableClipping(true);
|
|
}
|
|
|
|
if (fixupFor43) { // DG: gotta reset that before returning this function
|
|
dc->SetMenuScaleFix(false);
|
|
}
|
|
|
|
drawRect.Offset(-x, -y);
|
|
clientRect.Offset(-x, -y);
|
|
textRect.Offset(-x, -y);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetDC
|
|
================
|
|
*/
|
|
void idWindow::SetDC(idDeviceContext *d) {
|
|
dc = d;
|
|
//if (flags & WIN_DESKTOP) {
|
|
dc->SetSize(forceAspectWidth, forceAspectHeight);
|
|
//}
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
children[i]->SetDC(d);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ArchiveToDictionary
|
|
================
|
|
*/
|
|
void idWindow::ArchiveToDictionary(idDict *dict, bool useNames) {
|
|
//FIXME: rewrite without state
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
children[i]->ArchiveToDictionary(dict);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::InitFromDictionary
|
|
================
|
|
*/
|
|
void idWindow::InitFromDictionary(idDict *dict, bool byName) {
|
|
//FIXME: rewrite without state
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
children[i]->InitFromDictionary(dict);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::CalcClientRect
|
|
================
|
|
*/
|
|
void idWindow::CalcClientRect(float xofs, float yofs) {
|
|
drawRect = rect;
|
|
|
|
if ( flags & WIN_INVERTRECT ) {
|
|
drawRect.x = rect.x() - rect.w();
|
|
drawRect.y = rect.y() - rect.h();
|
|
}
|
|
|
|
if (flags & (WIN_HCENTER | WIN_VCENTER) && parent) {
|
|
// in this case treat xofs and yofs as absolute top left coords
|
|
// and ignore the original positioning
|
|
if (flags & WIN_HCENTER) {
|
|
drawRect.x = (parent->rect.w() - rect.w()) / 2;
|
|
} else {
|
|
drawRect.y = (parent->rect.h() - rect.h()) / 2;
|
|
}
|
|
}
|
|
|
|
drawRect.x += xofs;
|
|
drawRect.y += yofs;
|
|
|
|
clientRect = drawRect;
|
|
if (rect.h() > 0.0 && rect.w() > 0.0) {
|
|
|
|
if (flags & WIN_BORDER && borderSize != 0.0) {
|
|
clientRect.x += borderSize;
|
|
clientRect.y += borderSize;
|
|
clientRect.w -= borderSize;
|
|
clientRect.h -= borderSize;
|
|
}
|
|
|
|
textRect = clientRect;
|
|
textRect.x += 2.0;
|
|
textRect.w -= 2.0;
|
|
textRect.y += 2.0;
|
|
textRect.h -= 2.0;
|
|
|
|
textRect.x += textAlignx;
|
|
textRect.y += textAligny;
|
|
|
|
}
|
|
origin.Set( rect.x() + (rect.w() / 2 ), rect.y() + ( rect.h() / 2 ) );
|
|
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetupBackground
|
|
================
|
|
*/
|
|
void idWindow::SetupBackground() {
|
|
if (backGroundName.Length()) {
|
|
background = declManager->FindMaterial(backGroundName);
|
|
background->SetImageClassifications( 1 ); // just for resource tracking
|
|
if ( background && !background->TestMaterialFlag( MF_DEFAULTED ) ) {
|
|
background->SetSort(SS_GUI );
|
|
}
|
|
}
|
|
backGroundName.SetMaterialPtr(&background);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetupFromState
|
|
================
|
|
*/
|
|
void idWindow::SetupFromState() {
|
|
idStr str;
|
|
background = NULL;
|
|
|
|
SetupBackground();
|
|
|
|
if (borderSize) {
|
|
flags |= WIN_BORDER;
|
|
}
|
|
|
|
if (regList.FindReg("rotate") || regList.FindReg("shear")) {
|
|
flags |= WIN_TRANSFORM;
|
|
}
|
|
|
|
CalcClientRect(0,0);
|
|
if ( scripts[ ON_ACTION ] ) {
|
|
cursor = idDeviceContext::CURSOR_HAND;
|
|
flags |= WIN_CANFOCUS;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Moved
|
|
================
|
|
*/
|
|
void idWindow::Moved() {
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Sized
|
|
================
|
|
*/
|
|
void idWindow::Sized() {
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GainFocus
|
|
================
|
|
*/
|
|
void idWindow::GainFocus() {
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::LoseFocus
|
|
================
|
|
*/
|
|
void idWindow::LoseFocus() {
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GainCapture
|
|
================
|
|
*/
|
|
void idWindow::GainCapture() {
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::LoseCapture
|
|
================
|
|
*/
|
|
void idWindow::LoseCapture() {
|
|
flags &= ~WIN_CAPTURE;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetFlag
|
|
================
|
|
*/
|
|
void idWindow::SetFlag(unsigned int f) {
|
|
flags |= f;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ClearFlag
|
|
================
|
|
*/
|
|
void idWindow::ClearFlag(unsigned int f) {
|
|
flags &= ~f;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
idWindow::SetParent
|
|
================
|
|
*/
|
|
void idWindow::SetParent(idWindow *w) {
|
|
parent = w;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetCaptureChild
|
|
================
|
|
*/
|
|
idWindow *idWindow::GetCaptureChild() {
|
|
if (flags & WIN_DESKTOP) {
|
|
return gui->GetDesktop()->captureChild;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetFocusedChild
|
|
================
|
|
*/
|
|
idWindow *idWindow::GetFocusedChild() {
|
|
if (flags & WIN_DESKTOP) {
|
|
return gui->GetDesktop()->focusedChild;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
idWindow::SetFocus
|
|
================
|
|
*/
|
|
idWindow *idWindow::SetFocus(idWindow *w, bool scripts) {
|
|
// only one child can have the focus
|
|
idWindow *lastFocus = NULL;
|
|
if (w->flags & WIN_CANFOCUS) {
|
|
lastFocus = gui->GetDesktop()->focusedChild;
|
|
if ( lastFocus ) {
|
|
lastFocus->flags &= ~WIN_FOCUS;
|
|
lastFocus->LoseFocus();
|
|
}
|
|
|
|
// call on lose focus
|
|
if ( scripts && lastFocus ) {
|
|
// calling this broke all sorts of guis
|
|
// lastFocus->RunScript(ON_MOUSEEXIT);
|
|
}
|
|
// call on gain focus
|
|
if ( scripts && w ) {
|
|
// calling this broke all sorts of guis
|
|
// w->RunScript(ON_MOUSEENTER);
|
|
}
|
|
|
|
w->flags |= WIN_FOCUS;
|
|
w->GainFocus();
|
|
gui->GetDesktop()->focusedChild = w;
|
|
}
|
|
|
|
return lastFocus;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseScript
|
|
================
|
|
*/
|
|
bool idWindow::ParseScript(idParser *src, idGuiScriptList &list, int *timeParm, bool elseBlock ) {
|
|
|
|
bool ifElseBlock = false;
|
|
|
|
idToken token;
|
|
|
|
// scripts start with { ( unless parm is true ) and have ; separated command lists.. commands are command,
|
|
// arg.. basically we want everything between the { } as it will be interpreted at
|
|
// run time
|
|
|
|
if ( elseBlock ) {
|
|
src->ReadToken ( &token );
|
|
|
|
if ( !token.Icmp ( "if" ) ) {
|
|
ifElseBlock = true;
|
|
}
|
|
|
|
src->UnreadToken ( &token );
|
|
|
|
if ( !ifElseBlock && !src->ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
}
|
|
else if ( !src->ExpectTokenString( "{" ) ) {
|
|
return false;
|
|
}
|
|
|
|
int nest = 0;
|
|
|
|
while (1) {
|
|
if ( !src->ReadToken(&token) ) {
|
|
src->Error( "Unexpected end of file" );
|
|
return false;
|
|
}
|
|
|
|
if ( token == "{" ) {
|
|
nest++;
|
|
}
|
|
|
|
if ( token == "}" ) {
|
|
if (nest-- <= 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
idGuiScript *gs = new idGuiScript();
|
|
if (token.Icmp("if") == 0) {
|
|
gs->conditionReg = ParseExpression(src);
|
|
gs->ifList = new idGuiScriptList();
|
|
ParseScript(src, *gs->ifList, NULL);
|
|
if (src->ReadToken(&token)) {
|
|
if (token == "else") {
|
|
gs->elseList = new idGuiScriptList();
|
|
// pass true to indicate we are parsing an else condition
|
|
ParseScript(src, *gs->elseList, NULL, true );
|
|
} else {
|
|
src->UnreadToken(&token);
|
|
}
|
|
}
|
|
|
|
list.Append(gs);
|
|
|
|
// if we are parsing an else if then return out so
|
|
// the initial "if" parser can handle the rest of the tokens
|
|
if ( ifElseBlock ) {
|
|
return true;
|
|
}
|
|
continue;
|
|
} else {
|
|
src->UnreadToken(&token);
|
|
}
|
|
|
|
// empty { } is not allowed
|
|
if ( token == "{" ) {
|
|
src->Error ( "Unexpected {" );
|
|
delete gs;
|
|
return false;
|
|
}
|
|
|
|
gs->Parse(src);
|
|
list.Append(gs);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SaveExpressionParseState
|
|
================
|
|
*/
|
|
void idWindow::SaveExpressionParseState() {
|
|
saveTemps = (bool*)Mem_Alloc(MAX_EXPRESSION_REGISTERS * sizeof(bool));
|
|
memcpy(saveTemps, registerIsTemporary, MAX_EXPRESSION_REGISTERS * sizeof(bool));
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::RestoreExpressionParseState
|
|
================
|
|
*/
|
|
void idWindow::RestoreExpressionParseState() {
|
|
memcpy(registerIsTemporary, saveTemps, MAX_EXPRESSION_REGISTERS * sizeof(bool));
|
|
Mem_Free(saveTemps);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseScriptEntry
|
|
================
|
|
*/
|
|
bool idWindow::ParseScriptEntry(const char *name, idParser *src) {
|
|
for (int i = 0; i < SCRIPT_COUNT; i++) {
|
|
if (idStr::Icmp(name, ScriptNames[i]) == 0) {
|
|
delete scripts[i];
|
|
scripts[i] = new idGuiScriptList;
|
|
return ParseScript(src, *scripts[i]);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::DisableRegister
|
|
================
|
|
*/
|
|
void idWindow::DisableRegister(const char *_name) {
|
|
idRegister *reg = RegList()->FindReg(_name);
|
|
if (reg) {
|
|
reg->Enable(false);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::PostParse
|
|
================
|
|
*/
|
|
void idWindow::PostParse() {
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetWinVarOffset
|
|
================
|
|
*/
|
|
intptr_t idWindow::GetWinVarOffset( idWinVar *wv, drawWin_t* owner) {
|
|
intptr_t ret = -1;
|
|
|
|
if ( wv == &rect ) {
|
|
ret = (ptrdiff_t)&this->rect - (ptrdiff_t)this;
|
|
}
|
|
|
|
if ( wv == &backColor ) {
|
|
ret = (ptrdiff_t)&this->backColor - (ptrdiff_t)this;
|
|
}
|
|
|
|
if ( wv == &matColor ) {
|
|
ret = (ptrdiff_t)&this->matColor - (ptrdiff_t)this;
|
|
}
|
|
|
|
if ( wv == &foreColor ) {
|
|
ret = (ptrdiff_t)&this->foreColor - (ptrdiff_t)this;
|
|
}
|
|
|
|
if ( wv == &hoverColor ) {
|
|
ret = (ptrdiff_t)&this->hoverColor - (ptrdiff_t)this;
|
|
}
|
|
|
|
if ( wv == &borderColor ) {
|
|
ret = (ptrdiff_t)&this->borderColor - (ptrdiff_t)this;
|
|
}
|
|
|
|
if ( wv == &textScale ) {
|
|
ret = (ptrdiff_t)&this->textScale - (ptrdiff_t)this;
|
|
}
|
|
|
|
if ( wv == &rotate ) {
|
|
ret = (ptrdiff_t)&this->rotate - (ptrdiff_t)this;
|
|
}
|
|
|
|
if ( ret != -1 ) {
|
|
owner->win = this;
|
|
return ret;
|
|
}
|
|
|
|
for ( int i = 0; i < drawWindows.Num(); i++ ) {
|
|
if ( drawWindows[i].win ) {
|
|
ret = drawWindows[i].win->GetWinVarOffset( wv, owner );
|
|
} else {
|
|
ret = drawWindows[i].simp->GetWinVarOffset( wv, owner );
|
|
}
|
|
if ( ret != -1 ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetWinVarByName
|
|
================
|
|
*/
|
|
idWinVar *idWindow::GetWinVarByName(const char *_name, bool fixup, drawWin_t** owner) {
|
|
idWinVar *retVar = NULL;
|
|
|
|
if ( owner ) {
|
|
*owner = NULL;
|
|
}
|
|
|
|
if (idStr::Icmp(_name, "notime") == 0) {
|
|
retVar = &noTime;
|
|
}
|
|
if (idStr::Icmp(_name, "background") == 0) {
|
|
retVar = &backGroundName;
|
|
}
|
|
if (idStr::Icmp(_name, "visible") == 0) {
|
|
retVar = &visible;
|
|
}
|
|
if (idStr::Icmp(_name, "rect") == 0) {
|
|
retVar = ▭
|
|
}
|
|
if (idStr::Icmp(_name, "backColor") == 0) {
|
|
retVar = &backColor;
|
|
}
|
|
if (idStr::Icmp(_name, "matColor") == 0) {
|
|
retVar = &matColor;
|
|
}
|
|
if (idStr::Icmp(_name, "foreColor") == 0) {
|
|
retVar = &foreColor;
|
|
}
|
|
if (idStr::Icmp(_name, "hoverColor") == 0) {
|
|
retVar = &hoverColor;
|
|
}
|
|
if (idStr::Icmp(_name, "borderColor") == 0) {
|
|
retVar = &borderColor;
|
|
}
|
|
if (idStr::Icmp(_name, "textScale") == 0) {
|
|
retVar = &textScale;
|
|
}
|
|
if (idStr::Icmp(_name, "rotate") == 0) {
|
|
retVar = &rotate;
|
|
}
|
|
if (idStr::Icmp(_name, "noEvents") == 0) {
|
|
retVar = &noEvents;
|
|
}
|
|
if (idStr::Icmp(_name, "text") == 0) {
|
|
retVar = &text;
|
|
}
|
|
if (idStr::Icmp(_name, "backGroundName") == 0) {
|
|
retVar = &backGroundName;
|
|
}
|
|
if (idStr::Icmp(_name, "hidecursor") == 0) {
|
|
retVar = &hideCursor;
|
|
}
|
|
|
|
idStr key = _name;
|
|
bool guiVar = (key.Find(VAR_GUIPREFIX) >= 0);
|
|
int c = definedVars.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if (idStr::Icmp(_name, (guiVar) ? va("%s",definedVars[i]->GetName()) : definedVars[i]->GetName()) == 0) {
|
|
retVar = definedVars[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (retVar) {
|
|
if (fixup && *_name != '$') {
|
|
DisableRegister(_name);
|
|
}
|
|
|
|
if ( owner && parent ) {
|
|
*owner = parent->FindChildByName ( name );
|
|
}
|
|
|
|
return retVar;
|
|
}
|
|
|
|
int len = key.Length();
|
|
if ( len > 5 && guiVar ) {
|
|
idWinVar *var = new idWinStr;
|
|
var->Init(_name, this);
|
|
definedVars.Append(var);
|
|
return var;
|
|
} else if (fixup) {
|
|
int n = key.Find("::");
|
|
if (n > 0) {
|
|
idStr winName = key.Left(n);
|
|
idStr var = key.Right(key.Length() - n - 2);
|
|
drawWin_t *win = GetGui()->GetDesktop()->FindChildByName(winName);
|
|
if (win) {
|
|
if (win->win) {
|
|
return win->win->GetWinVarByName(var, false, owner);
|
|
} else {
|
|
if ( owner ) {
|
|
*owner = win;
|
|
}
|
|
return win->simp->GetWinVarByName(var);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseString
|
|
================
|
|
*/
|
|
void idWindow::ParseString(idParser *src, idStr &out) {
|
|
idToken tok;
|
|
if (src->ReadToken(&tok)) {
|
|
out = tok;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseVec4
|
|
================
|
|
*/
|
|
void idWindow::ParseVec4(idParser *src, idVec4 &out) {
|
|
idToken tok;
|
|
src->ReadToken(&tok);
|
|
out.x = atof(tok);
|
|
src->ExpectTokenString(",");
|
|
src->ReadToken(&tok);
|
|
out.y = atof(tok);
|
|
src->ExpectTokenString(",");
|
|
src->ReadToken(&tok);
|
|
out.z = atof(tok);
|
|
src->ExpectTokenString(",");
|
|
src->ReadToken(&tok);
|
|
out.w = atof(tok);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseInternalVar
|
|
================
|
|
*/
|
|
bool idWindow::ParseInternalVar(const char *_name, idParser *src) {
|
|
|
|
if (idStr::Icmp(_name, "showtime") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_SHOWTIME;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "showcoords") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_SHOWCOORDS;
|
|
}
|
|
return true;
|
|
}
|
|
// DG: added this window flag for Windows that should be scaled to 4:3
|
|
// (with "empty" bars left/right or above/below)
|
|
if (idStr::Icmp(_name, "scaleto43") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_SCALETO43;
|
|
}
|
|
return true;
|
|
}
|
|
// DG end
|
|
if (idStr::Icmp(_name, "forceaspectwidth") == 0) {
|
|
forceAspectWidth = src->ParseFloat();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "forceaspectheight") == 0) {
|
|
forceAspectHeight = src->ParseFloat();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "matscalex") == 0) {
|
|
matScalex = src->ParseFloat();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "matscaley") == 0) {
|
|
matScaley = src->ParseFloat();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "bordersize") == 0) {
|
|
borderSize = src->ParseFloat();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "nowrap") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_NOWRAP;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "shadow") == 0) {
|
|
textShadow = src->ParseInt();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "textalign") == 0) {
|
|
textAlign = src->ParseInt();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "textalignx") == 0) {
|
|
textAlignx = src->ParseFloat();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "textaligny") == 0) {
|
|
textAligny = src->ParseFloat();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "shear") == 0) {
|
|
shear.x = src->ParseFloat();
|
|
idToken tok;
|
|
src->ReadToken( &tok );
|
|
if ( tok.Icmp( "," ) ) {
|
|
src->Error( "Expected comma in shear definiation" );
|
|
return false;
|
|
}
|
|
shear.y = src->ParseFloat();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "wantenter") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_WANTENTER;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "naturalmatscale") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_NATURALMAT;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "noclip") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_NOCLIP;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "nocursor") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_NOCURSOR;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "menugui") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_MENUGUI;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "modal") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_MODAL;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "invertrect") == 0) {
|
|
if ( src->ParseBool() ) {
|
|
flags |= WIN_INVERTRECT;
|
|
}
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "name") == 0) {
|
|
ParseString(src, name);
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "play") == 0) {
|
|
common->Warning( "play encountered during gui parse.. see Robert\n" );
|
|
idStr playStr;
|
|
ParseString(src, playStr);
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "comment") == 0) {
|
|
ParseString(src, comment);
|
|
return true;
|
|
}
|
|
if ( idStr::Icmp( _name, "font" ) == 0 ) {
|
|
idStr fontStr;
|
|
ParseString( src, fontStr );
|
|
fontNum = dc->FindFont( fontStr );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseRegEntry
|
|
================
|
|
*/
|
|
bool idWindow::ParseRegEntry(const char *name, idParser *src) {
|
|
idStr work;
|
|
work = name;
|
|
work.ToLower();
|
|
|
|
idWinVar *var = GetWinVarByName(work, false);
|
|
if ( var ) {
|
|
for (int i = 0; i < NumRegisterVars; i++) {
|
|
if (idStr::Icmp(work, RegisterVars[i].name) == 0) {
|
|
regList.AddReg(work, RegisterVars[i].type, src, this, var);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// not predefined so just read the next token and add it to the state
|
|
idToken tok;
|
|
idVec4 v;
|
|
idWinInt *vari;
|
|
idWinFloat *varf;
|
|
idWinStr *vars;
|
|
if (src->ReadToken(&tok)) {
|
|
if (var) {
|
|
var->Set(tok);
|
|
return true;
|
|
}
|
|
switch (tok.type) {
|
|
case TT_NUMBER :
|
|
if (tok.subtype & TT_INTEGER) {
|
|
vari = new idWinInt();
|
|
*vari = atoi(tok);
|
|
vari->SetName(work);
|
|
definedVars.Append(vari);
|
|
} else if (tok.subtype & TT_FLOAT) {
|
|
varf = new idWinFloat();
|
|
*varf = atof(tok);
|
|
varf->SetName(work);
|
|
definedVars.Append(varf);
|
|
} else {
|
|
vars = new idWinStr();
|
|
*vars = tok;
|
|
vars->SetName(work);
|
|
definedVars.Append(vars);
|
|
}
|
|
break;
|
|
default :
|
|
vars = new idWinStr();
|
|
*vars = tok;
|
|
vars->SetName(work);
|
|
definedVars.Append(vars);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetInitialState
|
|
================
|
|
*/
|
|
void idWindow::SetInitialState(const char *_name) {
|
|
name = _name;
|
|
matScalex = 1.0;
|
|
matScaley = 1.0;
|
|
forceAspectWidth = 640.0;
|
|
forceAspectHeight = 480.0;
|
|
noTime = false;
|
|
visible = true;
|
|
flags = 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Parse
|
|
================
|
|
*/
|
|
bool idWindow::Parse( idParser *src, bool rebuild) {
|
|
idToken token, token2, token3, token4, token5, token6, token7;
|
|
idStr work;
|
|
|
|
if (rebuild) {
|
|
CleanUp();
|
|
}
|
|
|
|
drawWin_t dwt;
|
|
|
|
timeLineEvents.Clear();
|
|
transitions.Clear();
|
|
|
|
namedEvents.DeleteContents( true );
|
|
|
|
src->ExpectTokenType( TT_NAME, 0, &token );
|
|
|
|
SetInitialState(token);
|
|
|
|
src->ExpectTokenString( "{" );
|
|
src->ExpectAnyToken( &token );
|
|
|
|
bool ret = true;
|
|
|
|
// attach a window wrapper to the window if the gui editor is running
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
new rvGEWindowWrapper ( this, rvGEWindowWrapper::WT_NORMAL );
|
|
}
|
|
#endif
|
|
|
|
while( token != "}" ) {
|
|
// track what was parsed so we can maintain it for the guieditor
|
|
src->SetMarker ( );
|
|
|
|
if ( token == "windowDef" || token == "animationDef" ) {
|
|
if (token == "animationDef") {
|
|
visible = false;
|
|
rect = idRectangle(0,0,0,0);
|
|
}
|
|
src->ExpectTokenType( TT_NAME, 0, &token );
|
|
token2 = token;
|
|
src->UnreadToken(&token);
|
|
drawWin_t *dw = FindChildByName(token2.c_str());
|
|
if (dw && dw->win) {
|
|
SaveExpressionParseState();
|
|
dw->win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
} else {
|
|
idWindow *win = new idWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = NULL;
|
|
if (win->IsSimple()) {
|
|
idSimpleWindow *simple = new idSimpleWindow(win);
|
|
dwt.simp = simple;
|
|
drawWindows.Append(dwt);
|
|
delete win;
|
|
} else {
|
|
AddChild(win);
|
|
SetFocus(win,false);
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
}
|
|
}
|
|
else if ( token == "editDef" ) {
|
|
idEditWindow *win = new idEditWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "choiceDef" ) {
|
|
idChoiceWindow *win = new idChoiceWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "sliderDef" ) {
|
|
idSliderWindow *win = new idSliderWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "markerDef" ) {
|
|
idMarkerWindow *win = new idMarkerWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "bindDef" ) {
|
|
idBindWindow *win = new idBindWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "listDef" ) {
|
|
idListWindow *win = new idListWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "fieldDef" ) {
|
|
idFieldWindow *win = new idFieldWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "renderDef" ) {
|
|
idRenderWindow *win = new idRenderWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "gameSSDDef" ) {
|
|
idGameSSDWindow *win = new idGameSSDWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "gameBearShootDef" ) {
|
|
idGameBearShootWindow *win = new idGameBearShootWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
else if ( token == "gameBustOutDef" ) {
|
|
idGameBustOutWindow *win = new idGameBustOutWindow(dc, gui);
|
|
SaveExpressionParseState();
|
|
win->Parse(src, rebuild);
|
|
RestoreExpressionParseState();
|
|
AddChild(win);
|
|
win->SetParent(this);
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
drawWindows.Append(dwt);
|
|
}
|
|
//
|
|
// added new onEvent
|
|
else if ( token == "onNamedEvent" ) {
|
|
// Read the event name
|
|
if ( !src->ReadToken(&token) ) {
|
|
src->Error( "Expected event name" );
|
|
return false;
|
|
}
|
|
|
|
rvNamedEvent* ev = new rvNamedEvent ( token );
|
|
|
|
src->SetMarker ( );
|
|
|
|
if ( !ParseScript ( src, *ev->mEvent ) ) {
|
|
ret = false;
|
|
break;
|
|
}
|
|
|
|
// If we are in the gui editor then add the internal var to the
|
|
// the wrapper
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
idStr str;
|
|
idStr out;
|
|
|
|
// Grab the string from the last marker
|
|
src->GetStringFromMarker ( str, false );
|
|
|
|
// Parse it one more time to knock unwanted tabs out
|
|
idLexer src2( str, str.Length(), "", src->GetFlags() );
|
|
src2.ParseBracedSectionExact ( out, 1);
|
|
|
|
// Save the script
|
|
rvGEWindowWrapper::GetWrapper ( this )->GetScriptDict().Set ( va("onEvent %s", token.c_str()), out );
|
|
}
|
|
#endif
|
|
namedEvents.Append(ev);
|
|
}
|
|
else if ( token == "onTime" ) {
|
|
idTimeLineEvent *ev = new idTimeLineEvent;
|
|
|
|
if ( !src->ReadToken(&token) ) {
|
|
src->Error( "Unexpected end of file" );
|
|
return false;
|
|
}
|
|
ev->time = atoi(token.c_str());
|
|
|
|
// reset the mark since we dont want it to include the time
|
|
src->SetMarker ( );
|
|
|
|
if (!ParseScript(src, *ev->event, &ev->time)) {
|
|
ret = false;
|
|
break;
|
|
}
|
|
|
|
// add the script to the wrappers script list
|
|
// If we are in the gui editor then add the internal var to the
|
|
// the wrapper
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
idStr str;
|
|
idStr out;
|
|
|
|
// Grab the string from the last marker
|
|
src->GetStringFromMarker ( str, false );
|
|
|
|
// Parse it one more time to knock unwanted tabs out
|
|
idLexer src2( str, str.Length(), "", src->GetFlags() );
|
|
src2.ParseBracedSectionExact ( out, 1);
|
|
|
|
// Save the script
|
|
rvGEWindowWrapper::GetWrapper ( this )->GetScriptDict().Set ( va("onTime %d", ev->time), out );
|
|
}
|
|
#endif
|
|
// this is a timeline event
|
|
ev->pending = true;
|
|
timeLineEvents.Append(ev);
|
|
}
|
|
else if ( token == "definefloat" ) {
|
|
src->ReadToken(&token);
|
|
work = token;
|
|
work.ToLower();
|
|
idWinFloat *varf = new idWinFloat();
|
|
varf->SetName(work);
|
|
definedVars.Append(varf);
|
|
|
|
// add the float to the editors wrapper dict
|
|
// Set the marker after the float name
|
|
src->SetMarker ( );
|
|
|
|
// Read in the float
|
|
regList.AddReg(work, idRegister::FLOAT, src, this, varf);
|
|
|
|
// If we are in the gui editor then add the float to the defines
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
idStr str;
|
|
|
|
// Grab the string from the last marker and save it in the wrapper
|
|
src->GetStringFromMarker ( str, true );
|
|
rvGEWindowWrapper::GetWrapper ( this )->GetVariableDict().Set ( va("definefloat\t\"%s\"",token.c_str()), str );
|
|
}
|
|
#endif
|
|
}
|
|
else if ( token == "definevec4" ) {
|
|
src->ReadToken(&token);
|
|
work = token;
|
|
work.ToLower();
|
|
idWinVec4 *var = new idWinVec4();
|
|
var->SetName(work);
|
|
|
|
// set the marker so we can determine what was parsed
|
|
// set the marker after the vec4 name
|
|
src->SetMarker ( );
|
|
|
|
// FIXME: how about we add the var to the desktop instead of this window so it won't get deleted
|
|
// when this window is destoyed which even happens during parsing with simple windows ?
|
|
//definedVars.Append(var);
|
|
gui->GetDesktop()->definedVars.Append( var );
|
|
gui->GetDesktop()->regList.AddReg( work, idRegister::VEC4, src, gui->GetDesktop(), var );
|
|
|
|
// store the original vec4 for the editor
|
|
// If we are in the gui editor then add the float to the defines
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
idStr str;
|
|
|
|
// Grab the string from the last marker and save it in the wrapper
|
|
src->GetStringFromMarker ( str, true );
|
|
rvGEWindowWrapper::GetWrapper ( this )->GetVariableDict().Set ( va("definevec4\t\"%s\"",token.c_str()), str );
|
|
}
|
|
#endif
|
|
}
|
|
else if ( token == "float" ) {
|
|
src->ReadToken(&token);
|
|
work = token;
|
|
work.ToLower();
|
|
idWinFloat *varf = new idWinFloat();
|
|
varf->SetName(work);
|
|
definedVars.Append(varf);
|
|
|
|
// add the float to the editors wrapper dict
|
|
// set the marker to after the float name
|
|
src->SetMarker ( );
|
|
|
|
// Parse the float
|
|
regList.AddReg(work, idRegister::FLOAT, src, this, varf);
|
|
|
|
// If we are in the gui editor then add the float to the defines
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
idStr str;
|
|
|
|
// Grab the string from the last marker and save it in the wrapper
|
|
src->GetStringFromMarker ( str, true );
|
|
rvGEWindowWrapper::GetWrapper ( this )->GetVariableDict().Set ( va("float\t\"%s\"",token.c_str()), str );
|
|
}
|
|
#endif
|
|
}
|
|
else if (ParseScriptEntry(token, src)) {
|
|
// add the script to the wrappers script list
|
|
// If we are in the gui editor then add the internal var to the
|
|
// the wrapper
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
idStr str;
|
|
idStr out;
|
|
|
|
// Grab the string from the last marker
|
|
src->GetStringFromMarker ( str, false );
|
|
|
|
// Parse it one more time to knock unwanted tabs out
|
|
idLexer src2( str, str.Length(), "", src->GetFlags() );
|
|
src2.ParseBracedSectionExact ( out, 1);
|
|
|
|
// Save the script
|
|
rvGEWindowWrapper::GetWrapper ( this )->GetScriptDict().Set ( token, out );
|
|
}
|
|
#endif
|
|
} else if (ParseInternalVar(token, src)) {
|
|
// gui editor support
|
|
// If we are in the gui editor then add the internal var to the
|
|
// the wrapper
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
idStr str;
|
|
src->GetStringFromMarker ( str );
|
|
rvGEWindowWrapper::GetWrapper ( this )->SetStateKey ( token, str, false );
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
ParseRegEntry(token, src);
|
|
// hook into the main window parsing for the gui editor
|
|
// If we are in the gui editor then add the internal var to the
|
|
// the wrapper
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
idStr str;
|
|
src->GetStringFromMarker ( str );
|
|
rvGEWindowWrapper::GetWrapper ( this )->SetStateKey ( token, str, false );
|
|
}
|
|
#endif
|
|
}
|
|
if ( !src->ReadToken( &token ) ) {
|
|
src->Error( "Unexpected end of file" );
|
|
ret = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ret) {
|
|
EvalRegs(-1, true);
|
|
}
|
|
|
|
SetupFromState();
|
|
PostParse();
|
|
|
|
// hook into the main window parsing for the gui editor
|
|
// If we are in the gui editor then add the internal var to the
|
|
// the wrapper
|
|
#ifdef ID_ALLOW_TOOLS
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
rvGEWindowWrapper::GetWrapper ( this )->Finish ( );
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::FindSimpleWinByName
|
|
================
|
|
*/
|
|
idSimpleWindow *idWindow::FindSimpleWinByName(const char *_name) {
|
|
int c = drawWindows.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if (drawWindows[i].simp == NULL) {
|
|
continue;
|
|
}
|
|
if ( idStr::Icmp(drawWindows[i].simp->name, _name) == 0 ) {
|
|
return drawWindows[i].simp;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::FindChildByName
|
|
================
|
|
*/
|
|
drawWin_t *idWindow::FindChildByName(const char *_name) {
|
|
static drawWin_t dw;
|
|
if (idStr::Icmp(name,_name) == 0) {
|
|
dw.simp = NULL;
|
|
dw.win = this;
|
|
return &dw;
|
|
}
|
|
int c = drawWindows.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if (drawWindows[i].win) {
|
|
if (idStr::Icmp(drawWindows[i].win->name, _name) == 0) {
|
|
return &drawWindows[i];
|
|
}
|
|
drawWin_t *win = drawWindows[i].win->FindChildByName(_name);
|
|
if (win) {
|
|
return win;
|
|
}
|
|
} else {
|
|
if (idStr::Icmp(drawWindows[i].simp->name, _name) == 0) {
|
|
return &drawWindows[i];
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetStrPtrByName
|
|
================
|
|
*/
|
|
idStr* idWindow::GetStrPtrByName(const char *_name) {
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::AddTransition
|
|
================
|
|
*/
|
|
void idWindow::AddTransition(idWinVar *dest, idVec4 from, idVec4 to, int time, float accelTime, float decelTime) {
|
|
idTransitionData data;
|
|
data.data = dest;
|
|
data.interp.Init(gui->GetTime(), accelTime * time, decelTime * time, time, from, to);
|
|
transitions.Append(data);
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
idWindow::StartTransition
|
|
================
|
|
*/
|
|
void idWindow::StartTransition() {
|
|
flags |= WIN_INTRANSITION;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ResetCinematics
|
|
================
|
|
*/
|
|
void idWindow::ResetCinematics() {
|
|
if ( background ) {
|
|
background->ResetCinematicTime( gui->GetTime() );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ResetTime
|
|
================
|
|
*/
|
|
void idWindow::ResetTime(int t) {
|
|
|
|
timeLine = gui->GetTime() - t;
|
|
|
|
int i, c = timeLineEvents.Num();
|
|
for ( i = 0; i < c; i++ ) {
|
|
if ( timeLineEvents[i]->time >= t ) {
|
|
timeLineEvents[i]->pending = true;
|
|
}
|
|
}
|
|
|
|
noTime = false;
|
|
|
|
c = transitions.Num();
|
|
for ( i = 0; i < c; i++ ) {
|
|
idTransitionData *data = &transitions[i];
|
|
if ( data->interp.IsDone( gui->GetTime() ) && data->data ) {
|
|
transitions.RemoveIndex( i );
|
|
i--;
|
|
c--;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
idWindow::RunScriptList
|
|
================
|
|
*/
|
|
bool idWindow::RunScriptList(idGuiScriptList *src) {
|
|
if (src == NULL) {
|
|
return false;
|
|
}
|
|
src->Execute(this);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::RunScript
|
|
================
|
|
*/
|
|
bool idWindow::RunScript(int n) {
|
|
if (n >= ON_MOUSEENTER && n < SCRIPT_COUNT) {
|
|
return RunScriptList(scripts[n]);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ExpressionConstant
|
|
================
|
|
*/
|
|
int idWindow::ExpressionConstant(float f) {
|
|
int i;
|
|
|
|
for ( i = WEXP_REG_NUM_PREDEFINED ; i < expressionRegisters.Num() ; i++ ) {
|
|
if ( !registerIsTemporary[i] && expressionRegisters[i] == f ) {
|
|
return i;
|
|
}
|
|
}
|
|
if ( expressionRegisters.Num() == MAX_EXPRESSION_REGISTERS ) {
|
|
common->Warning( "expressionConstant: gui %s hit MAX_EXPRESSION_REGISTERS", gui->GetSourceFile() );
|
|
return 0;
|
|
}
|
|
|
|
int c = expressionRegisters.Num();
|
|
if (i > c) {
|
|
while (i > c) {
|
|
expressionRegisters.Append(-9999999);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
i = expressionRegisters.Append(f);
|
|
registerIsTemporary[i] = false;
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ExpressionTemporary
|
|
================
|
|
*/
|
|
int idWindow::ExpressionTemporary() {
|
|
if ( expressionRegisters.Num() == MAX_EXPRESSION_REGISTERS ) {
|
|
common->Warning( "expressionTemporary: gui %s hit MAX_EXPRESSION_REGISTERS", gui->GetSourceFile());
|
|
return 0;
|
|
}
|
|
int i = expressionRegisters.Num();
|
|
registerIsTemporary[i] = true;
|
|
i = expressionRegisters.Append(0);
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ExpressionOp
|
|
================
|
|
*/
|
|
wexpOp_t *idWindow::ExpressionOp() {
|
|
if ( ops.Num() == MAX_EXPRESSION_OPS ) {
|
|
common->Warning( "expressionOp: gui %s hit MAX_EXPRESSION_OPS", gui->GetSourceFile());
|
|
return &ops[0];
|
|
}
|
|
wexpOp_t wop;
|
|
memset(&wop, 0, sizeof(wexpOp_t));
|
|
int i = ops.Append(wop);
|
|
return &ops[i];
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::EmitOp
|
|
================
|
|
*/
|
|
|
|
intptr_t idWindow::EmitOp( intptr_t a, intptr_t b, wexpOpType_t opType, wexpOp_t **opp ) {
|
|
wexpOp_t *op;
|
|
/*
|
|
// optimize away identity operations
|
|
if ( opType == WOP_TYPE_ADD ) {
|
|
if ( !registerIsTemporary[a] && shaderRegisters[a] == 0 ) {
|
|
return b;
|
|
}
|
|
if ( !registerIsTemporary[b] && shaderRegisters[b] == 0 ) {
|
|
return a;
|
|
}
|
|
if ( !registerIsTemporary[a] && !registerIsTemporary[b] ) {
|
|
return ExpressionConstant( shaderRegisters[a] + shaderRegisters[b] );
|
|
}
|
|
}
|
|
if ( opType == WOP_TYPE_MULTIPLY ) {
|
|
if ( !registerIsTemporary[a] && shaderRegisters[a] == 1 ) {
|
|
return b;
|
|
}
|
|
if ( !registerIsTemporary[a] && shaderRegisters[a] == 0 ) {
|
|
return a;
|
|
}
|
|
if ( !registerIsTemporary[b] && shaderRegisters[b] == 1 ) {
|
|
return a;
|
|
}
|
|
if ( !registerIsTemporary[b] && shaderRegisters[b] == 0 ) {
|
|
return b;
|
|
}
|
|
if ( !registerIsTemporary[a] && !registerIsTemporary[b] ) {
|
|
return ExpressionConstant( shaderRegisters[a] * shaderRegisters[b] );
|
|
}
|
|
}
|
|
*/
|
|
op = ExpressionOp();
|
|
|
|
op->opType = opType;
|
|
op->a = a;
|
|
op->b = b;
|
|
op->c = ExpressionTemporary();
|
|
|
|
if (opp) {
|
|
*opp = op;
|
|
}
|
|
return op->c;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseEmitOp
|
|
================
|
|
*/
|
|
intptr_t idWindow::ParseEmitOp( idParser *src, intptr_t a, wexpOpType_t opType, int priority, wexpOp_t **opp ) {
|
|
intptr_t b = ParseExpressionPriority( src, priority );
|
|
return EmitOp( a, b, opType, opp );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseTerm
|
|
|
|
Returns a register index
|
|
=================
|
|
*/
|
|
intptr_t idWindow::ParseTerm( idParser *src, idWinVar *var, intptr_t component ) {
|
|
idToken token;
|
|
intptr_t a, b;
|
|
|
|
src->ReadToken( &token );
|
|
|
|
if ( token == "(" ) {
|
|
a = ParseExpression( src );
|
|
src->ExpectTokenString(")");
|
|
return a;
|
|
}
|
|
|
|
if ( !token.Icmp( "time" ) ) {
|
|
return WEXP_REG_TIME;
|
|
}
|
|
|
|
// parse negative numbers
|
|
if ( token == "-" ) {
|
|
src->ReadToken( &token );
|
|
if ( token.type == TT_NUMBER || token == "." ) {
|
|
return ExpressionConstant( -(float) token.GetFloatValue() );
|
|
}
|
|
src->Warning( "Bad negative number '%s'", token.c_str() );
|
|
return 0;
|
|
}
|
|
|
|
if ( token.type == TT_NUMBER || token == "." || token == "-" ) {
|
|
return ExpressionConstant( (float) token.GetFloatValue() );
|
|
}
|
|
|
|
// see if it is a table name
|
|
const idDeclTable *table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, token.c_str(), false ) );
|
|
if ( table ) {
|
|
a = table->Index();
|
|
// parse a table expression
|
|
src->ExpectTokenString("[");
|
|
b = ParseExpression(src);
|
|
src->ExpectTokenString("]");
|
|
return EmitOp( a, b, WOP_TYPE_TABLE );
|
|
}
|
|
|
|
if (var == NULL) {
|
|
var = GetWinVarByName(token, true);
|
|
}
|
|
if (var) {
|
|
a = (intptr_t)var;
|
|
//assert(dynamic_cast<idWinVec4*>(var));
|
|
var->Init(token, this);
|
|
b = component;
|
|
if (dynamic_cast<idWinVec4*>(var)) {
|
|
if (src->ReadToken(&token)) {
|
|
if (token == "[") {
|
|
b = ParseExpression(src);
|
|
src->ExpectTokenString("]");
|
|
} else {
|
|
src->UnreadToken(&token);
|
|
}
|
|
}
|
|
return EmitOp(a, b, WOP_TYPE_VAR);
|
|
} else if (dynamic_cast<idWinFloat*>(var)) {
|
|
return EmitOp(a, b, WOP_TYPE_VARF);
|
|
} else if (dynamic_cast<idWinInt*>(var)) {
|
|
return EmitOp(a, b, WOP_TYPE_VARI);
|
|
} else if (dynamic_cast<idWinBool*>(var)) {
|
|
return EmitOp(a, b, WOP_TYPE_VARB);
|
|
} else if (dynamic_cast<idWinStr*>(var)) {
|
|
return EmitOp(a, b, WOP_TYPE_VARS);
|
|
} else {
|
|
src->Warning("Var expression not vec4, float or int '%s'", token.c_str());
|
|
}
|
|
return 0;
|
|
} else {
|
|
// ugly but used for post parsing to fixup named vars
|
|
char *p = new char[token.Length()+1];
|
|
strcpy(p, token);
|
|
a = (intptr_t)p;
|
|
b = -2;
|
|
return EmitOp(a, b, WOP_TYPE_VAR);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idWindow::ParseExpressionPriority
|
|
|
|
Returns a register index
|
|
=================
|
|
*/
|
|
#define TOP_PRIORITY 4
|
|
intptr_t idWindow::ParseExpressionPriority( idParser *src, int priority, idWinVar *var, intptr_t component ) {
|
|
idToken token;
|
|
intptr_t a;
|
|
|
|
if ( priority == 0 ) {
|
|
return ParseTerm( src, var, component );
|
|
}
|
|
|
|
a = ParseExpressionPriority( src, priority - 1, var, component );
|
|
|
|
if ( !src->ReadToken( &token ) ) {
|
|
// we won't get EOF in a real file, but we can
|
|
// when parsing from generated strings
|
|
return a;
|
|
}
|
|
|
|
if ( priority == 1 && token == "*" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_MULTIPLY, priority );
|
|
}
|
|
if ( priority == 1 && token == "/" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_DIVIDE, priority );
|
|
}
|
|
if ( priority == 1 && token == "%" ) { // implied truncate both to integer
|
|
return ParseEmitOp( src, a, WOP_TYPE_MOD, priority );
|
|
}
|
|
if ( priority == 2 && token == "+" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_ADD, priority );
|
|
}
|
|
if ( priority == 2 && token == "-" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_SUBTRACT, priority );
|
|
}
|
|
if ( priority == 3 && token == ">" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_GT, priority );
|
|
}
|
|
if ( priority == 3 && token == ">=" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_GE, priority );
|
|
}
|
|
if ( priority == 3 && token == "<" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_LT, priority );
|
|
}
|
|
if ( priority == 3 && token == "<=" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_LE, priority );
|
|
}
|
|
if ( priority == 3 && token == "==" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_EQ, priority );
|
|
}
|
|
if ( priority == 3 && token == "!=" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_NE, priority );
|
|
}
|
|
if ( priority == 4 && token == "&&" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_AND, priority );
|
|
}
|
|
if ( priority == 4 && token == "||" ) {
|
|
return ParseEmitOp( src, a, WOP_TYPE_OR, priority );
|
|
}
|
|
if ( priority == 4 && token == "?" ) {
|
|
wexpOp_t *oop = NULL;
|
|
intptr_t o = ParseEmitOp( src, a, WOP_TYPE_COND, priority, &oop );
|
|
if ( !src->ReadToken( &token ) ) {
|
|
return o;
|
|
}
|
|
if (token == ":") {
|
|
a = ParseExpressionPriority( src, priority - 1, var );
|
|
oop->d = a;
|
|
}
|
|
return o;
|
|
}
|
|
|
|
// assume that anything else terminates the expression
|
|
// not too robust error checking...
|
|
|
|
src->UnreadToken( &token );
|
|
|
|
return a;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseExpression
|
|
|
|
Returns a register index
|
|
================
|
|
*/
|
|
intptr_t idWindow::ParseExpression(idParser *src, idWinVar *var, intptr_t component) {
|
|
return ParseExpressionPriority( src, TOP_PRIORITY, var );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ParseBracedExpression
|
|
================
|
|
*/
|
|
void idWindow::ParseBracedExpression(idParser *src) {
|
|
src->ExpectTokenString("{");
|
|
ParseExpression(src);
|
|
src->ExpectTokenString("}");
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idWindow::EvaluateRegisters
|
|
|
|
Parameters are taken from the localSpace and the renderView,
|
|
then all expressions are evaluated, leaving the shader registers
|
|
set to their apropriate values.
|
|
===============
|
|
*/
|
|
void idWindow::EvaluateRegisters(float *registers) {
|
|
int i, b;
|
|
wexpOp_t *op;
|
|
idVec4 v;
|
|
|
|
int erc = expressionRegisters.Num();
|
|
int oc = ops.Num();
|
|
// copy the constants
|
|
for ( i = WEXP_REG_NUM_PREDEFINED ; i < erc ; i++ ) {
|
|
registers[i] = expressionRegisters[i];
|
|
}
|
|
|
|
// copy the local and global parameters
|
|
registers[WEXP_REG_TIME] = gui->GetTime();
|
|
|
|
for ( i = 0 ; i < oc ; i++ ) {
|
|
op = &ops[i];
|
|
if (op->b == -2) {
|
|
continue;
|
|
}
|
|
switch( op->opType ) {
|
|
case WOP_TYPE_ADD:
|
|
registers[op->c] = registers[op->a] + registers[op->b];
|
|
break;
|
|
case WOP_TYPE_SUBTRACT:
|
|
registers[op->c] = registers[op->a] - registers[op->b];
|
|
break;
|
|
case WOP_TYPE_MULTIPLY:
|
|
registers[op->c] = registers[op->a] * registers[op->b];
|
|
break;
|
|
case WOP_TYPE_DIVIDE:
|
|
if ( registers[op->b] == 0.0f ) {
|
|
common->Warning( "Divide by zero in window '%s' in %s", GetName(), gui->GetSourceFile() );
|
|
registers[op->c] = registers[op->a];
|
|
} else {
|
|
registers[op->c] = registers[op->a] / registers[op->b];
|
|
}
|
|
break;
|
|
case WOP_TYPE_MOD:
|
|
b = (int)registers[op->b];
|
|
b = b != 0 ? b : 1;
|
|
registers[op->c] = (int)registers[op->a] % b;
|
|
break;
|
|
case WOP_TYPE_TABLE:
|
|
{
|
|
const idDeclTable *table = static_cast<const idDeclTable *>( declManager->DeclByIndex( DECL_TABLE, op->a ) );
|
|
registers[op->c] = table->TableLookup( registers[op->b] );
|
|
}
|
|
break;
|
|
case WOP_TYPE_GT:
|
|
registers[op->c] = registers[ op->a ] > registers[op->b];
|
|
break;
|
|
case WOP_TYPE_GE:
|
|
registers[op->c] = registers[ op->a ] >= registers[op->b];
|
|
break;
|
|
case WOP_TYPE_LT:
|
|
registers[op->c] = registers[ op->a ] < registers[op->b];
|
|
break;
|
|
case WOP_TYPE_LE:
|
|
registers[op->c] = registers[ op->a ] <= registers[op->b];
|
|
break;
|
|
case WOP_TYPE_EQ:
|
|
registers[op->c] = registers[ op->a ] == registers[op->b];
|
|
break;
|
|
case WOP_TYPE_NE:
|
|
registers[op->c] = registers[ op->a ] != registers[op->b];
|
|
break;
|
|
case WOP_TYPE_COND:
|
|
registers[op->c] = (registers[ op->a ]) ? registers[op->b] : registers[op->d];
|
|
break;
|
|
case WOP_TYPE_AND:
|
|
registers[op->c] = registers[ op->a ] && registers[op->b];
|
|
break;
|
|
case WOP_TYPE_OR:
|
|
registers[op->c] = registers[ op->a ] || registers[op->b];
|
|
break;
|
|
case WOP_TYPE_VAR:
|
|
if ( !op->a ) {
|
|
registers[op->c] = 0.0f;
|
|
break;
|
|
}
|
|
if ( op->b >= 0 && registers[op->b] >= 0 && registers[op->b] < 4 ) {
|
|
// grabs vector components
|
|
idWinVec4 *var = (idWinVec4 *)( op->a );
|
|
registers[op->c] = ((idVec4&)var)[registers[op->b]];
|
|
} else {
|
|
registers[op->c] = ((idWinVar*)(op->a))->x();
|
|
}
|
|
break;
|
|
case WOP_TYPE_VARS:
|
|
if (op->a) {
|
|
idWinStr *var = (idWinStr*)(op->a);
|
|
registers[op->c] = atof(var->c_str());
|
|
} else {
|
|
registers[op->c] = 0;
|
|
}
|
|
break;
|
|
case WOP_TYPE_VARF:
|
|
if (op->a) {
|
|
idWinFloat *var = (idWinFloat*)(op->a);
|
|
registers[op->c] = *var;
|
|
} else {
|
|
registers[op->c] = 0;
|
|
}
|
|
break;
|
|
case WOP_TYPE_VARI:
|
|
if (op->a) {
|
|
idWinInt *var = (idWinInt*)(op->a);
|
|
registers[op->c] = *var;
|
|
} else {
|
|
registers[op->c] = 0;
|
|
}
|
|
break;
|
|
case WOP_TYPE_VARB:
|
|
if (op->a) {
|
|
idWinBool *var = (idWinBool*)(op->a);
|
|
registers[op->c] = *var;
|
|
} else {
|
|
registers[op->c] = 0;
|
|
}
|
|
break;
|
|
default:
|
|
common->FatalError( "R_EvaluateExpression: bad opcode" );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ReadFromDemoFile
|
|
================
|
|
*/
|
|
void idWindow::ReadFromDemoFile( class idDemoFile *f, bool rebuild ) {
|
|
|
|
// should never hit unless we re-enable WRITE_GUIS
|
|
#ifndef WRITE_GUIS
|
|
assert( false );
|
|
#else
|
|
|
|
if (rebuild) {
|
|
CommonInit();
|
|
}
|
|
|
|
f->SetLog(true, "window1");
|
|
backGroundName = f->ReadHashString();
|
|
f->SetLog(true, backGroundName);
|
|
if ( backGroundName[0] ) {
|
|
background = declManager->FindMaterial(backGroundName);
|
|
} else {
|
|
background = NULL;
|
|
}
|
|
f->ReadUnsignedChar( cursor );
|
|
f->ReadUnsignedInt( flags );
|
|
f->ReadInt( timeLine );
|
|
f->ReadInt( lastTimeRun );
|
|
idRectangle rct = rect;
|
|
f->ReadFloat( rct.x );
|
|
f->ReadFloat( rct.y );
|
|
f->ReadFloat( rct.w );
|
|
f->ReadFloat( rct.h );
|
|
f->ReadFloat( drawRect.x );
|
|
f->ReadFloat( drawRect.y );
|
|
f->ReadFloat( drawRect.w );
|
|
f->ReadFloat( drawRect.h );
|
|
f->ReadFloat( clientRect.x );
|
|
f->ReadFloat( clientRect.y );
|
|
f->ReadFloat( clientRect.w );
|
|
f->ReadFloat( clientRect.h );
|
|
f->ReadFloat( textRect.x );
|
|
f->ReadFloat( textRect.y );
|
|
f->ReadFloat( textRect.w );
|
|
f->ReadFloat( textRect.h );
|
|
f->ReadFloat( xOffset);
|
|
f->ReadFloat( yOffset);
|
|
int i, c;
|
|
|
|
idStr work;
|
|
if (rebuild) {
|
|
f->SetLog(true, (work + "-scripts"));
|
|
for (i = 0; i < SCRIPT_COUNT; i++) {
|
|
bool b;
|
|
f->ReadBool( b );
|
|
if (b) {
|
|
delete scripts[i];
|
|
scripts[i] = new idGuiScriptList;
|
|
scripts[i]->ReadFromDemoFile(f);
|
|
}
|
|
}
|
|
|
|
f->SetLog(true, (work + "-timelines"));
|
|
f->ReadInt( c );
|
|
for (i = 0; i < c; i++) {
|
|
idTimeLineEvent *tl = new idTimeLineEvent;
|
|
f->ReadInt( tl->time );
|
|
f->ReadBool( tl->pending );
|
|
tl->event->ReadFromDemoFile(f);
|
|
if (rebuild) {
|
|
timeLineEvents.Append(tl);
|
|
} else {
|
|
assert(i < timeLineEvents.Num());
|
|
timeLineEvents[i]->time = tl->time;
|
|
timeLineEvents[i]->pending = tl->pending;
|
|
}
|
|
}
|
|
}
|
|
|
|
f->SetLog(true, (work + "-transitions"));
|
|
f->ReadInt( c );
|
|
for (i = 0; i < c; i++) {
|
|
idTransitionData td;
|
|
td.data = NULL;
|
|
f->ReadInt ( td.offset );
|
|
|
|
float startTime, accelTime, linearTime, decelTime;
|
|
idVec4 startValue, endValue;
|
|
f->ReadFloat( startTime );
|
|
f->ReadFloat( accelTime );
|
|
f->ReadFloat( linearTime );
|
|
f->ReadFloat( decelTime );
|
|
f->ReadVec4( startValue );
|
|
f->ReadVec4( endValue );
|
|
td.interp.Init( startTime, accelTime, decelTime, accelTime + linearTime + decelTime, startValue, endValue );
|
|
|
|
// read this for correct data padding with the win32 savegames
|
|
// the extrapolate is correctly initialized through the above Init call
|
|
int extrapolationType;
|
|
float duration;
|
|
idVec4 baseSpeed, speed;
|
|
float currentTime;
|
|
idVec4 currentValue;
|
|
f->ReadInt( extrapolationType );
|
|
f->ReadFloat( startTime );
|
|
f->ReadFloat( duration );
|
|
f->ReadVec4( startValue );
|
|
f->ReadVec4( baseSpeed );
|
|
f->ReadVec4( speed );
|
|
f->ReadFloat( currentTime );
|
|
f->ReadVec4( currentValue );
|
|
|
|
transitions.Append(td);
|
|
}
|
|
|
|
f->SetLog(true, (work + "-regstuff"));
|
|
if (rebuild) {
|
|
f->ReadInt( c );
|
|
for (i = 0; i < c; i++) {
|
|
wexpOp_t w;
|
|
f->ReadInt( (int&)w.opType );
|
|
f->ReadInt( w.a );
|
|
f->ReadInt( w.b );
|
|
f->ReadInt( w.c );
|
|
f->ReadInt( w.d );
|
|
ops.Append(w);
|
|
}
|
|
|
|
f->ReadInt( c );
|
|
for (i = 0; i < c; i++) {
|
|
float ff;
|
|
f->ReadFloat( ff );
|
|
expressionRegisters.Append(ff);
|
|
}
|
|
|
|
regList.ReadFromDemoFile(f);
|
|
|
|
}
|
|
f->SetLog(true, (work + "-children"));
|
|
f->ReadInt( c );
|
|
for (i = 0; i < c; i++) {
|
|
if (rebuild) {
|
|
idWindow *win = new idWindow(dc, gui);
|
|
win->ReadFromDemoFile(f);
|
|
AddChild(win);
|
|
} else {
|
|
for (int j = 0; j < c; j++) {
|
|
if (children[j]->childID == i) {
|
|
children[j]->ReadFromDemoFile(f,rebuild);
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* WRITE_GUIS */
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::WriteToDemoFile
|
|
================
|
|
*/
|
|
void idWindow::WriteToDemoFile( class idDemoFile *f ) {
|
|
// should never hit unless we re-enable WRITE_GUIS
|
|
#ifndef WRITE_GUIS
|
|
assert( false );
|
|
#else
|
|
|
|
f->SetLog(true, "window");
|
|
f->WriteHashString(backGroundName);
|
|
f->SetLog(true, backGroundName);
|
|
f->WriteUnsignedChar( cursor );
|
|
f->WriteUnsignedInt( flags );
|
|
f->WriteInt( timeLine );
|
|
f->WriteInt( lastTimeRun );
|
|
idRectangle rct = rect;
|
|
f->WriteFloat( rct.x );
|
|
f->WriteFloat( rct.y );
|
|
f->WriteFloat( rct.w );
|
|
f->WriteFloat( rct.h );
|
|
f->WriteFloat( drawRect.x );
|
|
f->WriteFloat( drawRect.y );
|
|
f->WriteFloat( drawRect.w );
|
|
f->WriteFloat( drawRect.h );
|
|
f->WriteFloat( clientRect.x );
|
|
f->WriteFloat( clientRect.y );
|
|
f->WriteFloat( clientRect.w );
|
|
f->WriteFloat( clientRect.h );
|
|
f->WriteFloat( textRect.x );
|
|
f->WriteFloat( textRect.y );
|
|
f->WriteFloat( textRect.w );
|
|
f->WriteFloat( textRect.h );
|
|
f->WriteFloat( xOffset );
|
|
f->WriteFloat( yOffset );
|
|
idStr work;
|
|
f->SetLog(true, work);
|
|
|
|
int i, c;
|
|
|
|
f->SetLog(true, (work + "-transitions"));
|
|
c = transitions.Num();
|
|
f->WriteInt( c );
|
|
for (i = 0; i < c; i++) {
|
|
f->WriteInt( 0 );
|
|
f->WriteInt( transitions[i].offset );
|
|
|
|
f->WriteFloat( transitions[i].interp.GetStartTime() );
|
|
f->WriteFloat( transitions[i].interp.GetAccelTime() );
|
|
f->WriteFloat( transitions[i].interp.GetLinearTime() );
|
|
f->WriteFloat( transitions[i].interp.GetDecelTime() );
|
|
f->WriteVec4( transitions[i].interp.GetStartValue() );
|
|
f->WriteVec4( transitions[i].interp.GetEndValue() );
|
|
|
|
// write to keep win32 render demo format compatiblity - we don't actually read them back anymore
|
|
f->WriteInt( transitions[i].interp.GetExtrapolate()->GetExtrapolationType() );
|
|
f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetStartTime() );
|
|
f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetDuration() );
|
|
f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetStartValue() );
|
|
f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetBaseSpeed() );
|
|
f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetSpeed() );
|
|
f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetCurrentTime() );
|
|
f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetCurrentValue() );
|
|
}
|
|
|
|
f->SetLog(true, (work + "-regstuff"));
|
|
|
|
f->SetLog(true, (work + "-children"));
|
|
c = children.Num();
|
|
f->WriteInt( c );
|
|
for (i = 0; i < c; i++) {
|
|
for (int j = 0; j < c; j++) {
|
|
if (children[j]->childID == i) {
|
|
children[j]->WriteToDemoFile(f);
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
#endif /* WRITE_GUIS */
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idWindow::WriteString
|
|
===============
|
|
*/
|
|
void idWindow::WriteSaveGameString( const char *string, idFile *savefile ) {
|
|
int len = strlen( string );
|
|
|
|
savefile->Write( &len, sizeof( len ) );
|
|
savefile->Write( string, len );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idWindow::WriteSaveGameTransition
|
|
===============
|
|
*/
|
|
void idWindow::WriteSaveGameTransition( idTransitionData &trans, idFile *savefile ) {
|
|
drawWin_t dw, *fdw;
|
|
idStr winName("");
|
|
dw.simp = NULL;
|
|
dw.win = NULL;
|
|
int offset = gui->GetDesktop()->GetWinVarOffset( trans.data, &dw );
|
|
if ( dw.win || dw.simp ) {
|
|
winName = ( dw.win ) ? dw.win->GetName() : dw.simp->name.c_str();
|
|
}
|
|
fdw = gui->GetDesktop()->FindChildByName( winName );
|
|
if ( offset != -1 && fdw && ( fdw->win || fdw->simp ) ) {
|
|
savefile->Write( &offset, sizeof( offset ) );
|
|
WriteSaveGameString( winName, savefile );
|
|
savefile->Write( &trans.interp, sizeof( trans.interp ) );
|
|
} else {
|
|
offset = -1;
|
|
savefile->Write( &offset, sizeof( offset ) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idWindow::ReadSaveGameTransition
|
|
===============
|
|
*/
|
|
void idWindow::ReadSaveGameTransition( idTransitionData &trans, idFile *savefile ) {
|
|
int offset;
|
|
|
|
savefile->Read( &offset, sizeof( offset ) );
|
|
if ( offset != -1 ) {
|
|
idStr winName;
|
|
ReadSaveGameString( winName, savefile );
|
|
savefile->Read( &trans.interp, sizeof( trans.interp ) );
|
|
trans.data = NULL;
|
|
trans.offset = offset;
|
|
if ( winName.Length() ) {
|
|
idWinStr *strVar = new idWinStr();
|
|
strVar->Set( winName );
|
|
trans.data = dynamic_cast< idWinVar* >( strVar );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idWindow::WriteToSaveGame
|
|
===============
|
|
*/
|
|
void idWindow::WriteToSaveGame( idFile *savefile ) {
|
|
int i;
|
|
|
|
WriteSaveGameString( cmd, savefile );
|
|
|
|
savefile->Write( &actualX, sizeof( actualX ) );
|
|
savefile->Write( &actualY, sizeof( actualY ) );
|
|
savefile->Write( &childID, sizeof( childID ) );
|
|
savefile->Write( &flags, sizeof( flags ) );
|
|
savefile->Write( &lastTimeRun, sizeof( lastTimeRun ) );
|
|
savefile->Write( &drawRect, sizeof( drawRect ) );
|
|
savefile->Write( &clientRect, sizeof( clientRect ) );
|
|
savefile->Write( &origin, sizeof( origin ) );
|
|
savefile->Write( &fontNum, sizeof( fontNum ) );
|
|
savefile->Write( &timeLine, sizeof( timeLine ) );
|
|
savefile->Write( &xOffset, sizeof( xOffset ) );
|
|
savefile->Write( &yOffset, sizeof( yOffset ) );
|
|
savefile->Write( &cursor, sizeof( cursor ) );
|
|
savefile->Write( &forceAspectWidth, sizeof( forceAspectWidth ) );
|
|
savefile->Write( &forceAspectHeight, sizeof( forceAspectHeight ) );
|
|
savefile->Write( &matScalex, sizeof( matScalex ) );
|
|
savefile->Write( &matScaley, sizeof( matScaley ) );
|
|
savefile->Write( &borderSize, sizeof( borderSize ) );
|
|
savefile->Write( &textAlign, sizeof( textAlign ) );
|
|
savefile->Write( &textAlignx, sizeof( textAlignx ) );
|
|
savefile->Write( &textAligny, sizeof( textAligny ) );
|
|
savefile->Write( &textShadow, sizeof( textShadow ) );
|
|
savefile->Write( &shear, sizeof( shear ) );
|
|
|
|
WriteSaveGameString( name, savefile );
|
|
WriteSaveGameString( comment, savefile );
|
|
|
|
// WinVars
|
|
noTime.WriteToSaveGame( savefile );
|
|
visible.WriteToSaveGame( savefile );
|
|
rect.WriteToSaveGame( savefile );
|
|
backColor.WriteToSaveGame( savefile );
|
|
matColor.WriteToSaveGame( savefile );
|
|
foreColor.WriteToSaveGame( savefile );
|
|
hoverColor.WriteToSaveGame( savefile );
|
|
borderColor.WriteToSaveGame( savefile );
|
|
textScale.WriteToSaveGame( savefile );
|
|
noEvents.WriteToSaveGame( savefile );
|
|
rotate.WriteToSaveGame( savefile );
|
|
text.WriteToSaveGame( savefile );
|
|
backGroundName.WriteToSaveGame( savefile );
|
|
hideCursor.WriteToSaveGame(savefile);
|
|
|
|
// Defined Vars
|
|
for ( i = 0; i < definedVars.Num(); i++ ) {
|
|
definedVars[i]->WriteToSaveGame( savefile );
|
|
}
|
|
|
|
savefile->Write( &textRect, sizeof( textRect ) );
|
|
|
|
// Window pointers saved as the child ID of the window
|
|
int winID;
|
|
|
|
winID = focusedChild ? focusedChild->childID : -1 ;
|
|
savefile->Write( &winID, sizeof( winID ) );
|
|
|
|
winID = captureChild ? captureChild->childID : -1 ;
|
|
savefile->Write( &winID, sizeof( winID ) );
|
|
|
|
winID = overChild ? overChild->childID : -1 ;
|
|
savefile->Write( &winID, sizeof( winID ) );
|
|
|
|
|
|
// Scripts
|
|
for ( i = 0; i < SCRIPT_COUNT; i++ ) {
|
|
if ( scripts[i] ) {
|
|
scripts[i]->WriteToSaveGame( savefile );
|
|
}
|
|
}
|
|
|
|
// TimeLine Events
|
|
for ( i = 0; i < timeLineEvents.Num(); i++ ) {
|
|
if ( timeLineEvents[i] ) {
|
|
savefile->Write( &timeLineEvents[i]->pending, sizeof( timeLineEvents[i]->pending ) );
|
|
savefile->Write( &timeLineEvents[i]->time, sizeof( timeLineEvents[i]->time ) );
|
|
if ( timeLineEvents[i]->event ) {
|
|
timeLineEvents[i]->event->WriteToSaveGame( savefile );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Transitions
|
|
int num = transitions.Num();
|
|
|
|
savefile->Write( &num, sizeof( num ) );
|
|
for ( i = 0; i < transitions.Num(); i++ ) {
|
|
WriteSaveGameTransition( transitions[ i ], savefile );
|
|
}
|
|
|
|
|
|
// Named Events
|
|
for ( i = 0; i < namedEvents.Num(); i++ ) {
|
|
if ( namedEvents[i] ) {
|
|
WriteSaveGameString( namedEvents[i]->mName, savefile );
|
|
if ( namedEvents[i]->mEvent ) {
|
|
namedEvents[i]->mEvent->WriteToSaveGame( savefile );
|
|
}
|
|
}
|
|
}
|
|
|
|
// regList
|
|
regList.WriteToSaveGame( savefile );
|
|
|
|
|
|
// Save children
|
|
for ( i = 0; i < drawWindows.Num(); i++ ) {
|
|
drawWin_t window = drawWindows[i];
|
|
|
|
if ( window.simp ) {
|
|
window.simp->WriteToSaveGame( savefile );
|
|
} else if ( window.win ) {
|
|
window.win->WriteToSaveGame( savefile );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idWindow::ReadSaveGameString
|
|
===============
|
|
*/
|
|
void idWindow::ReadSaveGameString( idStr &string, idFile *savefile ) {
|
|
int len;
|
|
|
|
savefile->Read( &len, sizeof( len ) );
|
|
if ( len < 0 ) {
|
|
common->Warning( "idWindow::ReadSaveGameString: invalid length" );
|
|
}
|
|
|
|
string.Fill( ' ', len );
|
|
savefile->Read( &string[0], len );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idWindow::ReadFromSaveGame
|
|
===============
|
|
*/
|
|
void idWindow::ReadFromSaveGame( idFile *savefile ) {
|
|
int i;
|
|
|
|
transitions.Clear();
|
|
|
|
ReadSaveGameString( cmd, savefile );
|
|
|
|
savefile->Read( &actualX, sizeof( actualX ) );
|
|
savefile->Read( &actualY, sizeof( actualY ) );
|
|
savefile->Read( &childID, sizeof( childID ) );
|
|
savefile->Read( &flags, sizeof( flags ) );
|
|
savefile->Read( &lastTimeRun, sizeof( lastTimeRun ) );
|
|
savefile->Read( &drawRect, sizeof( drawRect ) );
|
|
savefile->Read( &clientRect, sizeof( clientRect ) );
|
|
savefile->Read( &origin, sizeof( origin ) );
|
|
savefile->Read( &fontNum, sizeof( fontNum ) );
|
|
savefile->Read( &timeLine, sizeof( timeLine ) );
|
|
savefile->Read( &xOffset, sizeof( xOffset ) );
|
|
savefile->Read( &yOffset, sizeof( yOffset ) );
|
|
savefile->Read( &cursor, sizeof( cursor ) );
|
|
savefile->Read( &forceAspectWidth, sizeof( forceAspectWidth ) );
|
|
savefile->Read( &forceAspectHeight, sizeof( forceAspectHeight ) );
|
|
savefile->Read( &matScalex, sizeof( matScalex ) );
|
|
savefile->Read( &matScaley, sizeof( matScaley ) );
|
|
savefile->Read( &borderSize, sizeof( borderSize ) );
|
|
savefile->Read( &textAlign, sizeof( textAlign ) );
|
|
savefile->Read( &textAlignx, sizeof( textAlignx ) );
|
|
savefile->Read( &textAligny, sizeof( textAligny ) );
|
|
savefile->Read( &textShadow, sizeof( textShadow ) );
|
|
savefile->Read( &shear, sizeof( shear ) );
|
|
|
|
ReadSaveGameString( name, savefile );
|
|
ReadSaveGameString( comment, savefile );
|
|
|
|
// WinVars
|
|
noTime.ReadFromSaveGame( savefile );
|
|
visible.ReadFromSaveGame( savefile );
|
|
rect.ReadFromSaveGame( savefile );
|
|
backColor.ReadFromSaveGame( savefile );
|
|
matColor.ReadFromSaveGame( savefile );
|
|
foreColor.ReadFromSaveGame( savefile );
|
|
hoverColor.ReadFromSaveGame( savefile );
|
|
borderColor.ReadFromSaveGame( savefile );
|
|
textScale.ReadFromSaveGame( savefile );
|
|
noEvents.ReadFromSaveGame( savefile );
|
|
rotate.ReadFromSaveGame( savefile );
|
|
text.ReadFromSaveGame( savefile );
|
|
backGroundName.ReadFromSaveGame( savefile );
|
|
|
|
if ( session->GetSaveGameVersion() >= 17 ) {
|
|
hideCursor.ReadFromSaveGame(savefile);
|
|
} else {
|
|
hideCursor = false;
|
|
}
|
|
|
|
// Defined Vars
|
|
for ( i = 0; i < definedVars.Num(); i++ ) {
|
|
definedVars[i]->ReadFromSaveGame( savefile );
|
|
}
|
|
|
|
savefile->Read( &textRect, sizeof( textRect ) );
|
|
|
|
// Window pointers saved as the child ID of the window
|
|
int winID = -1;
|
|
|
|
savefile->Read( &winID, sizeof( winID ) );
|
|
for ( i = 0; i < children.Num(); i++ ) {
|
|
if ( children[i]->childID == winID ) {
|
|
focusedChild = children[i];
|
|
}
|
|
}
|
|
savefile->Read( &winID, sizeof( winID ) );
|
|
for ( i = 0; i < children.Num(); i++ ) {
|
|
if ( children[i]->childID == winID ) {
|
|
captureChild = children[i];
|
|
}
|
|
}
|
|
savefile->Read( &winID, sizeof( winID ) );
|
|
for ( i = 0; i < children.Num(); i++ ) {
|
|
if ( children[i]->childID == winID ) {
|
|
overChild = children[i];
|
|
}
|
|
}
|
|
|
|
// Scripts
|
|
for ( i = 0; i < SCRIPT_COUNT; i++ ) {
|
|
if ( scripts[i] ) {
|
|
scripts[i]->ReadFromSaveGame( savefile );
|
|
}
|
|
}
|
|
|
|
// TimeLine Events
|
|
for ( i = 0; i < timeLineEvents.Num(); i++ ) {
|
|
if ( timeLineEvents[i] ) {
|
|
savefile->Read( &timeLineEvents[i]->pending, sizeof( timeLineEvents[i]->pending ) );
|
|
savefile->Read( &timeLineEvents[i]->time, sizeof( timeLineEvents[i]->time ) );
|
|
if ( timeLineEvents[i]->event ) {
|
|
timeLineEvents[i]->event->ReadFromSaveGame( savefile );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Transitions
|
|
int num;
|
|
savefile->Read( &num, sizeof( num ) );
|
|
for ( i = 0; i < num; i++ ) {
|
|
idTransitionData trans;
|
|
trans.data = NULL;
|
|
ReadSaveGameTransition( trans, savefile );
|
|
if ( trans.data ) {
|
|
transitions.Append( trans );
|
|
}
|
|
}
|
|
|
|
|
|
// Named Events
|
|
for ( i = 0; i < namedEvents.Num(); i++ ) {
|
|
if ( namedEvents[i] ) {
|
|
ReadSaveGameString( namedEvents[i]->mName, savefile );
|
|
if ( namedEvents[i]->mEvent ) {
|
|
namedEvents[i]->mEvent->ReadFromSaveGame( savefile );
|
|
}
|
|
}
|
|
}
|
|
|
|
// regList
|
|
regList.ReadFromSaveGame( savefile );
|
|
|
|
// Read children
|
|
for ( i = 0; i < drawWindows.Num(); i++ ) {
|
|
drawWin_t window = drawWindows[i];
|
|
|
|
if ( window.simp ) {
|
|
window.simp->ReadFromSaveGame( savefile );
|
|
} else if ( window.win ) {
|
|
window.win->ReadFromSaveGame( savefile );
|
|
}
|
|
}
|
|
|
|
if ( flags & WIN_DESKTOP ) {
|
|
FixupTransitions();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idWindow::NumTransitions
|
|
===============
|
|
*/
|
|
int idWindow::NumTransitions() {
|
|
int c = transitions.Num();
|
|
for ( int i = 0; i < children.Num(); i++ ) {
|
|
c += children[i]->NumTransitions();
|
|
}
|
|
return c;
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
idWindow::FixupTransitions
|
|
===============
|
|
*/
|
|
void idWindow::FixupTransitions() {
|
|
int i, c = transitions.Num();
|
|
for ( i = 0; i < c; i++ ) {
|
|
drawWin_t *dw = gui->GetDesktop()->FindChildByName( ( ( idWinStr* )transitions[i].data )->c_str() );
|
|
delete transitions[i].data;
|
|
transitions[i].data = NULL;
|
|
if ( dw && ( dw->win || dw->simp ) ){
|
|
if ( dw->win ) {
|
|
if ( transitions[i].offset == (ptrdiff_t)&this->rect - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->win->rect;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->backColor - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->win->backColor;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->matColor - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->win->matColor;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->foreColor - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->win->foreColor;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->borderColor - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->win->borderColor;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->textScale - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->win->textScale;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->rotate - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->win->rotate;
|
|
}
|
|
} else {
|
|
if ( transitions[i].offset == (ptrdiff_t)&this->rect - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->simp->rect;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->backColor - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->simp->backColor;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->matColor - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->simp->matColor;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->foreColor - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->simp->foreColor;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->borderColor - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->simp->borderColor;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->textScale - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->simp->textScale;
|
|
} else if ( transitions[i].offset == (ptrdiff_t)&this->rotate - (ptrdiff_t)this ) {
|
|
transitions[i].data = &dw->simp->rotate;
|
|
}
|
|
}
|
|
}
|
|
if ( transitions[i].data == NULL ) {
|
|
transitions.RemoveIndex( i );
|
|
i--;
|
|
c--;
|
|
}
|
|
}
|
|
for ( c = 0; c < children.Num(); c++ ) {
|
|
children[c]->FixupTransitions();
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
idWindow::AddChild
|
|
===============
|
|
*/
|
|
void idWindow::AddChild(idWindow *win) {
|
|
win->childID = children.Append(win);
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::FixupParms
|
|
================
|
|
*/
|
|
void idWindow::FixupParms() {
|
|
int i;
|
|
int c = children.Num();
|
|
for (i = 0; i < c; i++) {
|
|
children[i]->FixupParms();
|
|
}
|
|
for (i = 0; i < SCRIPT_COUNT; i++) {
|
|
if (scripts[i]) {
|
|
scripts[i]->FixupParms(this);
|
|
}
|
|
}
|
|
|
|
c = timeLineEvents.Num();
|
|
for (i = 0; i < c; i++) {
|
|
timeLineEvents[i]->event->FixupParms(this);
|
|
}
|
|
|
|
c = namedEvents.Num();
|
|
for (i = 0; i < c; i++) {
|
|
namedEvents[i]->mEvent->FixupParms(this);
|
|
}
|
|
|
|
c = ops.Num();
|
|
for (i = 0; i < c; i++) {
|
|
if (ops[i].b == -2) {
|
|
// need to fix this up
|
|
const char *p = (const char*)(ops[i].a);
|
|
idWinVar *var = GetWinVarByName(p, true);
|
|
delete []p;
|
|
ops[i].a = (intptr_t)var;
|
|
ops[i].b = -1;
|
|
}
|
|
}
|
|
|
|
|
|
if (flags & WIN_DESKTOP) {
|
|
CalcRects(0,0);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::IsSimple
|
|
================
|
|
*/
|
|
bool idWindow::IsSimple() {
|
|
|
|
// dont do simple windows when in gui editor
|
|
if ( com_editors & EDITOR_GUI ) {
|
|
return false;
|
|
}
|
|
|
|
if (ops.Num()) {
|
|
return false;
|
|
}
|
|
if (flags & (WIN_HCENTER | WIN_VCENTER)) {
|
|
return false;
|
|
}
|
|
if (children.Num() || drawWindows.Num()) {
|
|
return false;
|
|
}
|
|
for (int i = 0; i < SCRIPT_COUNT; i++) {
|
|
if (scripts[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
if (timeLineEvents.Num()) {
|
|
return false;
|
|
}
|
|
|
|
if ( namedEvents.Num() ) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ContainsStateVars
|
|
================
|
|
*/
|
|
bool idWindow::ContainsStateVars() {
|
|
if ( updateVars.Num() ) {
|
|
return true;
|
|
}
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if ( children[i]->ContainsStateVars() ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::Interactive
|
|
================
|
|
*/
|
|
bool idWindow::Interactive() {
|
|
if ( scripts[ ON_ACTION ] ) {
|
|
return true;
|
|
}
|
|
int c = children.Num();
|
|
for (int i = 0; i < c; i++) {
|
|
if (children[i]->Interactive()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetChildWinVarVal
|
|
================
|
|
*/
|
|
void idWindow::SetChildWinVarVal(const char *name, const char *var, const char *val) {
|
|
drawWin_t *dw = FindChildByName(name);
|
|
idWinVar *wv = NULL;
|
|
if (dw && dw->simp) {
|
|
wv = dw->simp->GetWinVarByName(var);
|
|
} else if (dw && dw->win) {
|
|
wv = dw->win->GetWinVarByName(var);
|
|
}
|
|
if (wv) {
|
|
wv->Set(val);
|
|
wv->SetEval(false);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
idWindow::FindChildByPoint
|
|
|
|
Finds the window under the given point
|
|
================
|
|
*/
|
|
idWindow* idWindow::FindChildByPoint ( float x, float y, idWindow** below ) {
|
|
int c = children.Num();
|
|
|
|
// If we are looking for a window below this one then
|
|
// the next window should be good, but this one wasnt it
|
|
if ( *below == this ) {
|
|
*below = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
if ( !Contains ( drawRect, x, y ) ) {
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = c - 1; i >= 0 ; i-- ) {
|
|
idWindow* found = children[i]->FindChildByPoint ( x, y, below );
|
|
if ( found ) {
|
|
if ( *below ) {
|
|
continue;
|
|
}
|
|
|
|
return found;
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::FindChildByPoint
|
|
================
|
|
*/
|
|
idWindow* idWindow::FindChildByPoint ( float x, float y, idWindow* below )
|
|
{
|
|
return FindChildByPoint ( x, y, &below );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetChildCount
|
|
|
|
Returns the number of children
|
|
================
|
|
*/
|
|
int idWindow::GetChildCount ( void )
|
|
{
|
|
return drawWindows.Num ( );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetChild
|
|
|
|
Returns the child window at the given index
|
|
================
|
|
*/
|
|
idWindow* idWindow::GetChild ( int index )
|
|
{
|
|
return drawWindows[index].win;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::GetChildIndex
|
|
|
|
Returns the index of the given child window
|
|
================
|
|
*/
|
|
int idWindow::GetChildIndex ( idWindow* window ) {
|
|
int find;
|
|
for ( find = 0; find < drawWindows.Num(); find ++ ) {
|
|
if ( drawWindows[find].win == window ) {
|
|
return find;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::RemoveChild
|
|
|
|
Removes the child from the list of children. Note that the child window being
|
|
removed must still be deallocated by the caller
|
|
================
|
|
*/
|
|
void idWindow::RemoveChild ( idWindow *win ) {
|
|
int find;
|
|
|
|
// Remove the child window
|
|
children.Remove ( win );
|
|
|
|
for ( find = 0; find < drawWindows.Num(); find ++ )
|
|
{
|
|
if ( drawWindows[find].win == win )
|
|
{
|
|
drawWindows.RemoveIndex ( find );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::InsertChild
|
|
|
|
Inserts the given window as a child into the given location in the zorder.
|
|
================
|
|
*/
|
|
bool idWindow::InsertChild ( idWindow *win, idWindow* before )
|
|
{
|
|
AddChild ( win );
|
|
|
|
win->parent = this;
|
|
|
|
drawWin_t dwt;
|
|
dwt.simp = NULL;
|
|
dwt.win = win;
|
|
|
|
// If not inserting before anything then just add it at the end
|
|
if ( before ) {
|
|
int index;
|
|
index = GetChildIndex ( before );
|
|
if ( index != -1 ) {
|
|
drawWindows.Insert ( dwt, index );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
drawWindows.Append ( dwt );
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ScreenToClient
|
|
================
|
|
*/
|
|
void idWindow::ScreenToClient ( idRectangle* r ) {
|
|
int x;
|
|
int y;
|
|
idWindow* p;
|
|
|
|
for ( p = this, x = 0, y = 0; p; p = p->parent ) {
|
|
x += p->rect.x();
|
|
y += p->rect.y();
|
|
}
|
|
|
|
r->x -= x;
|
|
r->y -= y;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::ClientToScreen
|
|
================
|
|
*/
|
|
void idWindow::ClientToScreen ( idRectangle* r ) {
|
|
int x;
|
|
int y;
|
|
idWindow* p;
|
|
|
|
for ( p = this, x = 0, y = 0; p; p = p->parent ) {
|
|
x += p->rect.x();
|
|
y += p->rect.y();
|
|
}
|
|
|
|
r->x += x;
|
|
r->y += y;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::SetDefaults
|
|
|
|
Set the window do a default window with no text, no background and
|
|
default colors, etc..
|
|
================
|
|
*/
|
|
void idWindow::SetDefaults ( void ) {
|
|
forceAspectWidth = 640.0f;
|
|
forceAspectHeight = 480.0f;
|
|
matScalex = 1;
|
|
matScaley = 1;
|
|
borderSize = 0;
|
|
noTime = false;
|
|
visible = true;
|
|
textAlign = 0;
|
|
textAlignx = 0;
|
|
textAligny = 0;
|
|
noEvents = false;
|
|
rotate = 0;
|
|
shear.Zero();
|
|
textScale = 0.35f;
|
|
backColor.Zero();
|
|
foreColor = idVec4(1, 1, 1, 1);
|
|
hoverColor = idVec4(1, 1, 1, 1);
|
|
matColor = idVec4(1, 1, 1, 1);
|
|
borderColor.Zero();
|
|
text = "";
|
|
|
|
background = NULL;
|
|
backGroundName = "";
|
|
}
|
|
|
|
/*
|
|
================
|
|
idWindow::UpdateFromDictionary
|
|
|
|
The editor only has a dictionary to work with so the easiest way to push the
|
|
values of the dictionary onto the window is for the window to interpret the
|
|
dictionary as if were a file being parsed.
|
|
================
|
|
*/
|
|
bool idWindow::UpdateFromDictionary ( idDict& dict ) {
|
|
const idKeyValue* kv;
|
|
int i;
|
|
|
|
SetDefaults ( );
|
|
|
|
// Clear all registers since they will get recreated
|
|
regList.Reset ( );
|
|
expressionRegisters.Clear ( );
|
|
ops.Clear ( );
|
|
|
|
for ( i = 0; i < dict.GetNumKeyVals(); i ++ ) {
|
|
kv = dict.GetKeyVal ( i );
|
|
|
|
// Special case name
|
|
if ( !kv->GetKey().Icmp ( "name" ) ) {
|
|
name = kv->GetValue();
|
|
continue;
|
|
}
|
|
|
|
idParser src( kv->GetValue().c_str(), kv->GetValue().Length(), "",
|
|
LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
|
|
if ( !ParseInternalVar ( kv->GetKey(), &src ) ) {
|
|
// Kill the old register since the parse reg entry will add a new one
|
|
if ( !ParseRegEntry ( kv->GetKey(), &src ) ) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
EvalRegs(-1, true);
|
|
|
|
SetupFromState();
|
|
PostParse();
|
|
|
|
return true;
|
|
}
|