added OnClose callback

more tests
minor fixes
Controls
David Dormagen 2013-04-07 22:52:45 +02:00
parent c2ba7e65d7
commit 1c05f22d41
15 changed files with 337 additions and 78 deletions

View File

@ -0,0 +1,7 @@
[DefCore]
id=MenuStyle_Grid
Version=4,10,0,0
Category=C4D_StaticBack
Width=1
Height=1
Offset=-1,-1

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

View File

@ -0,0 +1,54 @@
/**
Grid
Shows a simple grid menu.
*/
#include MenuStyle_List
local Name = "Grid Menu";
func Construction()
{
inherited(...);
this.Style = MENU_GridLayout;
}
// custom_menu_id should be passed if the menu was manually opened and not via Open()
func AddItem(symbol, string text, user_ID, proplist target, command, parameter, custom_entry, custom_menu_id)
{
custom_menu_id = custom_menu_id ?? menu_id;
var on_hover = MenuAction_SetTag(nil, 0, "OnHover");
if (on_mouse_over_callback)
on_hover = [on_hover, MenuAction_Call(this, "DoCallback", on_mouse_over_callback)];
var on_hover_stop = MenuAction_SetTag(nil, 0, "Std");
if (on_mouse_out_callback)
on_hover_stop = [on_hover_stop, MenuAction_Call(this, "DoCallback", on_mouse_out_callback)];
var ID = GetLength(entries) + 1;
if (!custom_entry)
{
custom_entry = {Hgt = [0, 64], Wdt = [0, 64], desc = {Y = [1000, -15]}};
custom_entry.Symbol = symbol;
custom_entry.desc.Text = text;
custom_entry.desc.Style = MENU_TextRight;
custom_entry.ID = ID;
custom_entry.Target = this;
custom_entry.Priority = ID;
custom_entry.BackgroundColor = {Std = 0, OnHover = 0x50ff0000};
custom_entry.OnClick = MenuAction_Call(this, "OnClick");
custom_entry.OnMouseIn = on_hover;
custom_entry.OnMouseOut = on_hover_stop;
}
entries[ID - 1] = [target, command, parameter, user_ID];
this[Format("menuChild%d", ID)] = custom_entry;
// need to add to existing menu?
if (custom_menu_id)
{
var temp = {child = custom_entry};
CustomMenuUpdate(temp, custom_menu_id, this.ID, this);
}
return custom_entry;
}

View File

@ -0,0 +1,2 @@
Name=Gitter
Description=Ein einfaches Gittermenü.

View File

@ -0,0 +1,2 @@
Name=List
Description=Shows a simple list menu.

View File

@ -17,6 +17,15 @@ func Construction()
entries = [];
this.Style = MENU_VerticalLayout;
this.Target = this;
this.ID = 0xffffff;
this.OnClose = MenuAction_Call(this, "OnCloseCallback");
}
func OnCloseCallback()
{
menu_id = 0;
Close();
}
func Close()
@ -45,8 +54,11 @@ func SetMouseOutCallback(proplist target, callback)
on_mouse_out_callback = [target, callback];
}
func AddItem(symbol, string text, user_ID, proplist target, command, parameter, custom_entry)
// custom_menu_id should be passed if the menu was manually opened and not via Open()
func AddItem(symbol, string text, user_ID, proplist target, command, parameter, custom_entry, custom_menu_id)
{
custom_menu_id = custom_menu_id ?? menu_id;
var on_hover = MenuAction_SetTag(nil, 0, "OnHover");
if (on_mouse_over_callback)
on_hover = [on_hover, MenuAction_Call(this, "DoCallback", on_mouse_over_callback)];
@ -73,9 +85,33 @@ func AddItem(symbol, string text, user_ID, proplist target, command, parameter,
entries[ID - 1] = [target, command, parameter, user_ID];
this[Format("menuChild%d", ID)] = custom_entry;
// need to add to existing menu?
if (custom_menu_id)
{
var temp = {child = custom_entry};
CustomMenuUpdate(temp, custom_menu_id, this.ID, this);
}
return custom_entry;
}
// can be used when the menu has already been opened
// needs to be passed the menu ID if the menu was not opened using Open()
func RemoveItem(user_ID, int custom_menu_id)
{
custom_menu_id = custom_menu_id ?? menu_id;
for (var i = 0; i < GetLength(entries); ++i)
{
var ID = i+1;
if (!entries[i]) continue;
if (entries[i][3] != user_ID) continue;
CustomMenuClose(custom_menu_id, ID, this);
entries[i] = nil;
return true;
}
return false;
}
func DoCall(int ID, command, proplist target, bool noclose, int player)
{
var self = this; // safety
@ -86,7 +122,6 @@ func DoCall(int ID, command, proplist target, bool noclose, int player)
{
if (target->Call(command ?? entry[1], entry[2], entry[3], player) == -1) return;
}
Log("self: %v, noclose: %d, permanent: %d", self, noclose, permanent);
if (self)
if (!noclose && !permanent)
Close();

View File

@ -1,2 +1,2 @@
Name=List
Name=Liste
Description=Ein einfaches Listenmenü.

View File

@ -39,6 +39,23 @@ global func Menu_AddMargin(proplist submenu, int marginX, int marginY)
return true;
}
global func Menu_AddCloseButton(proplist menu, proplist target, string callback, parameter)
{
var close_button =
{
Priority = 0x0fffff,
X = [1000, -32], Y = 0,
Wdt = 1000, Hgt = [0, 32],
Symbol = Icon_Cancel,
BackgroundColor = {Std = 0, Hover = 0x50ffff00},
OnMouseIn = MenuAction_SetTag(nil, nil, "Hover"),
OnMouseOut = MenuAction_SetTag(nil, nil, "Std"),
OnClick = MenuAction_Call(target, callback, parameter)
};
Menu_AddSubmenu(close_button, menu);
return close_button;
}
global func Menu_UpdateText(string text, int menu, int submenu, object target)
{
var update = {Text = text};

View File

@ -5,30 +5,40 @@ func Initialize()
var starter_menu =
{
Style = MENU_Multiple,
X = [1000], Y = [0, -100],
Wdt = [1000, 200], Hgt = [0, 100],
text = {Style = MENU_TextVCenter | MENU_TextHCenter, Text = "OPEN MENU"}
Decoration = GUI_MenuDeco,
X = [1000, -100], Y = [0, 50],
Wdt = [1000], Hgt = [0, 100],
text = {Style = MENU_TextVCenter | MENU_TextHCenter, Text = "OPEN MENU"},
BackgroundColor = {Std = 0, Hover = 0xffff0000},
OnMouseIn = MenuAction_SetTag(nil, nil, "Hover"),
OnMouseOut = MenuAction_SetTag(nil, nil, "Std"),
OnClick = MenuAction_Call(Scenario, "StartMenu")
};
CustomMenuOpen(starter_menu);
}
/* -------------------------------- MAIN ----------------------------- */
func InitializePlayer(plr)
func CloseCurrentMenu()
{
Schedule(nil, "Scenario->StartMenu()", 5, 0);
}
CustomMenuClose(active_menu);
active_menu = 0;
}
/* -------------------------------- MAIN ----------------------------- */
func MainOnHover(parameter, int ID)
{
Menu_UpdateText(parameter, active_menu, 9999);
}
func StartMenu(plr)
{
if (active_menu)
CustomMenuClose(active_menu);
var main_menu =
{
Decoration = GUI_MenuDeco,
head = {Hgt = [0, 50], Text = "Please choose a test!", Style = MENU_TextHCenter | MENU_TextVCenter, IDs = 0},
body = {Y = [0, 60], right = {X = 500, BackgroundColor = 0x50ffffff } },
};
Menu_AddCloseButton(main_menu, Scenario, "CloseCurrentMenu");
var menu = CreateCustomMenu(MenuStyle_List);
main_menu.body.left = menu;
@ -36,6 +46,8 @@ func StartMenu(plr)
menu->SetMouseOverCallback(Scenario, "MainOnHover");
menu->AddItem(Chest, "Test Multiple Lists (Inventory)", nil, Scenario, "StartMultipleListTest", "Shows multiple list-style menus in one big menu.");
menu->AddItem(Rule_TeamAccount, "Test Client/Host (Scenario Options)", nil, Scenario, "StartScenarioOptionsTest", "Shows how to display a dialogue that behaves differently for players.");
menu->AddItem(Clonk, "Test Multiple Windows (Player List)", nil, Scenario, "StartPlayerListTest", "Shows how to display a permanent info dialogue.");
menu->AddItem(Lorry, "Tests Two Grid Menus (Trade Menu)", nil, Scenario, "StartTransferTest", "Shows how to work with two grid menus.");
active_menu = CustomMenuOpen(main_menu);
}
@ -53,6 +65,7 @@ func StartMultipleListTest()
head = { ID = 999, Hgt = [0, 50], Text = "Inventory: <c ff0000>Empty</c>", Style = MENU_TextHCenter | MENU_TextVCenter, BackgroundColor = 0x55000000},
contents = { Y = [0, 50], X = [0, 20], Wdt = [1000, -20] },
};
Menu_AddCloseButton(menu, Scenario, "CloseCurrentMenu");
var inventory = [[Sword, Axe, Club], [IronBomb, Dynamite, Boompack, Firestone], [Bow, Musket, Javelin], [Shield, Bread, Sproutberry, CookedMushroom]];
var x = [0, [500, 20], 0, [500, 20]], y = [0, 0, [500, 20], [500, 20]], w = [[500, -20], 1000, [500, -20], 1000], h = [[500, -20], [500, -20], 1000, 1000];
@ -149,6 +162,7 @@ func StartScenarioOptionsTest(parameter, int ID, int player)
};
Menu_AddMargin(menu.right.hostdesc, 25, 25);
Menu_AddMargin(menu.right.clientdesc, 25, 25);
Menu_AddCloseButton(menu, Scenario, "CloseCurrentMenu");
var def, rules =[], i = 0;
while (def = GetDefinition(i++))
@ -169,7 +183,7 @@ func StartScenarioOptionsTest(parameter, int ID, int player)
{
Target = scenoptions_dummies[0],
Priority = 1,
BackgroundColor = {Std = 0, Hover = 0x50ff0000, On = 0x5000ff00},
BackgroundColor = {Std = 0, Hover = 0x50ff0000, On = 0x2000ff00},
OnMouseIn = {
Std = [MenuAction_Call(Scenario, "ScenOptsUpdateDesc", [rule.def, rule.ID, false]), MenuAction_SetTag(nil, nil, "Hover")],
On = MenuAction_Call(Scenario, "ScenOptsUpdateDesc", [rule.def, rule.ID, true])
@ -179,6 +193,12 @@ func StartScenarioOptionsTest(parameter, int ID, int player)
Hover = [MenuAction_Call(Scenario, "ScenOptsActivate", [rule.def, rule.ID]), MenuAction_SetTag(nil, nil, "On")],
On = [MenuAction_Call(Scenario, "ScenOptsDeactivate", [rule.def, rule.ID]), MenuAction_SetTag(nil, nil, "Hover")],
},
},
tick =
{
X = [1000, -60], Y = [500, -15],
Wdt = [1000, -30], Hgt =[500, 15],
Symbol = {Std = 0, Unticked = 0, Ticked = Icon_Ok}
}
};
Menu_AddSubmenu(subm, menu.list);
@ -191,11 +211,13 @@ func ScenOptsActivate(int player, int ID, int subwindowID, object target, data)
{
if (!ObjectCount(Find_ID(data[0])))
CreateObject(data[0]);
CustomMenuSetTag("Ticked", active_menu, data[1], nil);
}
func ScenOptsDeactivate(int player, int ID, int subwindowID, object target, data)
{
RemoveAll(Find_ID(data[0]));
CustomMenuSetTag("Unticked", active_menu, data[1], nil);
}
func ScenOptsUpdateDesc(int player, int ID, int subwindowID, object target, data)
@ -204,4 +226,125 @@ func ScenOptsUpdateDesc(int player, int ID, int subwindowID, object target, data
if (!data[2])
text = data[0].Description;
Menu_UpdateText(text, active_menu, 1, scenoptions_dummies[0]);
}
/* ------------------------ player list test ----------------------------- */
static player_list_menu;
func StartPlayerListTest(parameter, int ID, int player)
{
if (player_list_menu)
{
CustomMenuClose(player_list_menu);
player_list_menu = nil;
return -1;
}
var menu =
{
X = [1000, -150], Y = [0, 100],
Wdt = [1000, -5], Hgt = [0, 200],
Style = MENU_Multiple | MENU_VerticalLayout | MENU_FitChildren,
BackgroundColor = 0x30000000,
};
var player_names = [];
for (var i = 0; i < 15; ++i)
{
var p = GetPlayerByIndex(i);
var name;
if (p == NO_OWNER) name = Format("Player %d", i + 1);
else name = GetTaggedPlayerName(p);
var subm =
{
Priority = i,
Hgt = [0, 25],
Text = name,
Style = MENU_TextRight | MENU_TextVCenter,
icon =
{
Symbol = Clonk,
Wdt = [0, 25]
}
};
Menu_AddSubmenu(subm, menu);
}
player_list_menu = CustomMenuOpen(menu);
return -1; // keep open
}
/* ------------------------ transfer test ----------------------------- */
static transfer_left, transfer_right, transfer_menus, transfer_id_count;
func StartTransferTest()
{
CustomMenuClose(active_menu);
if (transfer_left == nil)
{
transfer_left = [Rock, Loam, Wood, Metal, Nugget, Coal, Shovel, Sword, Bow, Arrow, Boompack];
transfer_right = [Clonk];
transfer_menus = [];
transfer_id_count = 1;
}
// layout: headline and two submenus
var menu =
{
head = { Hgt = [0, 50], Text = "Welcome to the trade menu!", Style = MENU_TextHCenter | MENU_TextVCenter, BackgroundColor = 0x55000000},
contents = { Y = [0, 50], X = [0, 20], Wdt = [1000, -20] },
};
Menu_AddCloseButton(menu, Scenario, "CloseCurrentMenu");
for (var i = 0; i < 2; ++i)
{
var deco = { Decoration = GUI_MenuDeco, Text = "FROM", Style = MENU_TextHCenter};
if (i == 1)
{
deco.X = 500;
deco.Text = "TO";
}
else deco.Wdt = 500;
var m = CreateCustomMenu(MenuStyle_Grid);
deco.menu = m;
Menu_AddSubmenu(deco, menu.contents);
Menu_AddMargin(m, 20, 20);
var a = transfer_left;
if (i == 1) a = transfer_right;
for (var c = 0; c < GetLength(a); ++c)
{
var obj = a[c];
m->AddItem(obj, obj.Name, ++transfer_id_count, Scenario, "SelectTransferGood", [obj, i]);
}
transfer_menus[i] = m;
}
active_menu = CustomMenuOpen(menu);
}
func SelectTransferGood(data, int user_id, int player)
{
var obj = data[0];
var fromLeft = 0 == data[1];
var menu = transfer_menus[data[1]];
// first, move item from array to array
var from = transfer_left, to = transfer_right;
if (!fromLeft)
{
from = transfer_right;
to = transfer_left;
}
var found = false;
for (var i = 0; i < GetLength(from); ++i)
{
if (from[i] != obj) continue;
found = true;
PushBack(to, obj);
RemoveArrayIndex(from, i);
break;
}
if (!found) return -1;
if (!menu->RemoveItem(user_id, active_menu)) Log("remove fail!");
transfer_menus[1 - data[1]]->AddItem(obj, obj.Name, user_id, Scenario, "SelectTransferGood", [obj, 1 - data[1]], nil, active_menu);
return -1;
}

View File

@ -429,7 +429,6 @@ C4ControlMenuCommand::C4ControlMenuCommand(int32_t actionID, int32_t player, int
void C4ControlMenuCommand::Execute() const
{
LogF("C4ControlMenuCommand::Execute: %d::%d::%d, %d", menuID, subwindowID, actionID, target);
// invalid action? The action needs to be in bounds!
if (actionType < 0 || actionType >= C4MenuWindowPropertyName::_lastProp)
{

View File

@ -2127,15 +2127,12 @@ static int FnCustomMenuOpen(C4PropList * _this, C4PropList *menu)
::MenuWindowRoot.AddChild(window);
if (!window->CreateFromPropList(menu))
if (!window->CreateFromPropList(menu, true))
{
::MenuWindowRoot.RemoveChild(window, false);
return 0;
}
window->SetTag(&Strings.P[P_Std]);
return window->GetID();
}
@ -2178,10 +2175,10 @@ static bool FxCustomMenuUpdate(C4PropList *_this, C4PropList *update, int32_t me
{
C4MenuWindow *subwindow = window->GetSubWindow(childID, target);
if (!subwindow) return false;
subwindow->CreateFromPropList(update);
subwindow->CreateFromPropList(update, false, true);
return true;
}
window->CreateFromPropList(update);
window->CreateFromPropList(update, false, true);
return true;
}
@ -2632,8 +2629,8 @@ C4ScriptConstDef C4ScriptGameConstMap[]=
{ "MENU_SetTag" ,C4V_Int, C4MenuWindowActionID::SetTag },
{ "MENU_Call" ,C4V_Int, C4MenuWindowActionID::Call },
{ "MENU_GridLayout" ,C4V_Int, C4MenuWindowStyleFlag::Grid },
{ "MENU_VerticalLayout" ,C4V_Int, C4MenuWindowStyleFlag::Vertical },
{ "MENU_GridLayout" ,C4V_Int, C4MenuWindowStyleFlag::GridLayout },
{ "MENU_VerticalLayout" ,C4V_Int, C4MenuWindowStyleFlag::VerticalLayout },
{ "MENU_TextVCenter" ,C4V_Int, C4MenuWindowStyleFlag::TextVCenter },
{ "MENU_TextHCenter" ,C4V_Int, C4MenuWindowStyleFlag::TextHCenter },
{ "MENU_TextRight" ,C4V_Int, C4MenuWindowStyleFlag::TextRight },

View File

@ -72,7 +72,7 @@ bool C4MenuWindowAction::Init(C4ValueArray *array, int32_t index)
// an array of actions?
if (array->GetItem(0).getArray())
{
LogF("..initing multi-action event (index %d)", index);
//LogF("..initing multi-action event (index %d)", index);
// add action to action chain?
if (index+1 < array->GetSize())
{
@ -115,8 +115,7 @@ bool C4MenuWindowAction::Init(C4ValueArray *array, int32_t index)
default:
return false;
}
if (index > 0)
LogF("..chained action setup OK");
action = newAction;
return true;
}
@ -124,7 +123,7 @@ bool C4MenuWindowAction::Init(C4ValueArray *array, int32_t index)
void C4MenuWindowAction::Execute(C4MenuWindow *parent, int32_t player, unsigned int tag, int32_t actionType)
{
assert(parent && "C4MenuWindow::Execute must always be called with parent");
LogF("Excuting action (nextAction: %x, target: %x, text: %s, type: %d)", nextAction, target, text->GetCStr(), actionType);
//LogF("Excuting action (nextAction: %x, subwID: %d, target: %x, text: %s, type: %d)", nextAction, subwindowID, target, text->GetCStr(), actionType);
// invalid ID? can be set by removal of target object
if (action)
{
@ -145,7 +144,6 @@ void C4MenuWindowAction::Execute(C4MenuWindow *parent, int32_t player, unsigned
break;
// the action needs to be synchronized! Assemble command and put it into control queue!
Game.Input.Add(CID_MenuCommand, new C4ControlMenuCommand(id, player, main->GetID(), parent->GetID(), parent->target, tag, actionType));
Log("syncing command...");
break;
}
@ -172,7 +170,6 @@ void C4MenuWindowAction::Execute(C4MenuWindow *parent, int32_t player, unsigned
if (nextAction)
{
Log("..executing chained action..");
nextAction->Execute(parent, player, tag, actionType);
}
}
@ -192,7 +189,7 @@ bool C4MenuWindowAction::ExecuteCommand(int32_t actionID, C4MenuWindow *parent,
main = from;
from = from->parent;
}
LogF("command synced.. target: %x, targetObj: %x, func: %s", target, target->GetObject(), text->GetCStr());
//LogF("command synced.. target: %x, targetObj: %x, func: %s", target, target->GetObject(), text->GetCStr());
C4AulParSet Pars(C4VInt(player), C4VInt(main->GetID()), C4VInt(parent->GetID()), C4VObj(parent->target), value);
target->Call(text->GetCStr(), &Pars);
return true;
@ -277,6 +274,7 @@ void C4MenuWindowProperty::CleanUp(Prop &prop)
case onClickAction:
case onMouseInAction:
case onMouseOutAction:
case onCloseAction:
if (prop.action) delete prop.action;
break;
case text:
@ -389,6 +387,7 @@ void C4MenuWindowProperty::Set(const C4Value &value, unsigned int hash)
case C4MenuWindowPropertyName::onClickAction:
case C4MenuWindowPropertyName::onMouseInAction:
case C4MenuWindowPropertyName::onMouseOutAction:
case C4MenuWindowPropertyName::onCloseAction:
{
C4ValueArray *array = value.getArray();
if (array)
@ -421,6 +420,7 @@ void C4MenuWindowProperty::ClearPointers(C4Object *pObj)
case C4MenuWindowPropertyName::onClickAction:
case C4MenuWindowPropertyName::onMouseInAction:
case C4MenuWindowPropertyName::onMouseOutAction:
case C4MenuWindowPropertyName::onCloseAction:
if (iter->second.action)
iter->second.action->ClearPointers(pObj);
break;
@ -488,6 +488,7 @@ void C4MenuWindow::Init()
props[C4MenuWindowPropertyName::onClickAction].SetNull(hash);
props[C4MenuWindowPropertyName::onMouseInAction].SetNull(hash);
props[C4MenuWindowPropertyName::onMouseOutAction].SetNull(hash);
props[C4MenuWindowPropertyName::onCloseAction].SetNull(hash);
props[C4MenuWindowPropertyName::style].SetNull(hash);
props[C4MenuWindowPropertyName::priority].SetNull(hash);
@ -525,7 +526,7 @@ void C4MenuWindow::SetArrayTupleProperty(const C4Value &property, C4MenuWindowPr
else props[first].Set(property, hash);
}
bool C4MenuWindow::CreateFromPropList(C4PropList *proplist)
bool C4MenuWindow::CreateFromPropList(C4PropList *proplist, bool resetStdTag, bool isUpdate)
{
assert(parent && "MenuWindow created from proplist without parent (fails for ID tag)");
@ -605,6 +606,8 @@ bool C4MenuWindow::CreateFromPropList(C4PropList *proplist)
props[C4MenuWindowPropertyName::onMouseInAction].Set(property, standardHash);
else if(&Strings.P[P_OnMouseOut] == key)
props[C4MenuWindowPropertyName::onMouseOutAction].Set(property, standardHash);
else if(&Strings.P[P_OnClose] == key)
props[C4MenuWindowPropertyName::onCloseAction].Set(property, standardHash);
else if(&Strings.P[P_Style] == key)
{
props[C4MenuWindowPropertyName::style].Set(property, standardHash);
@ -624,15 +627,20 @@ bool C4MenuWindow::CreateFromPropList(C4PropList *proplist)
C4MenuWindow *child = new C4MenuWindow();
AddChild(child);
if (!child->CreateFromPropList(subwindow))
if (!child->CreateFromPropList(subwindow, isUpdate == true, false))
RemoveChild(child, false);
else
layoutUpdateRequired = true;
}
}
}
if (layoutUpdateRequired)
parent->lastDrawPosition.dirty = 2;
if (resetStdTag)
SetTag(&Strings.P[P_Std]);
return true;
}
@ -648,6 +656,7 @@ void C4MenuWindow::ClearPointers(C4Object *pObj)
props[C4MenuWindowPropertyName::onClickAction].ClearPointers(pObj);
props[C4MenuWindowPropertyName::onMouseInAction].ClearPointers(pObj);
props[C4MenuWindowPropertyName::onMouseOutAction].ClearPointers(pObj);
props[C4MenuWindowPropertyName::onCloseAction].ClearPointers(pObj);
// can't iterate directly over the children, since they might get deleted in the process
std::vector<C4MenuWindow*> temp;
@ -665,7 +674,7 @@ C4MenuWindow *C4MenuWindow::AddChild(C4MenuWindow *child)
{
child->SetID(GenerateMenuID());
child->isMainWindow = true;
LogF("adding main window: %d [I am %d, root: %d]", child->GetID(), id, int(this == &::MenuWindowRoot));
//LogF("adding main window: %d [I am %d, root: %d]", child->GetID(), id, int(this == &::MenuWindowRoot));
}
children.push_back(child);
return child;
@ -683,7 +692,7 @@ void C4MenuWindow::ChildWithIDRemoved(C4MenuWindow *child)
{
if (iter->second != child) continue;
childrenIDMap.erase(iter);
LogF("child-map-size: %d, remov %d [I am %d]", childrenIDMap.size(), child->GetID(), id);
//LogF("child-map-size: %d, remov %d [I am %d]", childrenIDMap.size(), child->GetID(), id);
return;
}
}
@ -694,7 +703,7 @@ void C4MenuWindow::ChildGotID(C4MenuWindow *child)
if (!isMainWindow)
return parent->ChildGotID(child);
childrenIDMap.insert(std::make_pair(child->GetID(), child));
LogF("child+map+size: %d, added %d [I am %d]", childrenIDMap.size(), child->GetID(), id);
//LogF("child+map+size: %d, added %d [I am %d]", childrenIDMap.size(), child->GetID(), id);
}
C4MenuWindow *C4MenuWindow::GetChildByID(int32_t child)
@ -758,18 +767,27 @@ void C4MenuWindow::Close()
ClearChildren(true);
// make call to target object if applicable
if (target)
C4MenuWindowAction *action = props[C4MenuWindowPropertyName::onCloseAction].GetAction();
if (action)
{
// todo
action->Execute(this, NO_OWNER, props[C4MenuWindowPropertyName::onCloseAction].GetCurrentTag(), C4MenuWindowPropertyName::onCloseAction);
}
LogF("C4MenuWindow::Close, parent: %d [I am %d]", parent ? parent->GetID() : 0, id);
//LogF("C4MenuWindow::Close, parent: %d [I am %d]", parent ? parent->GetID() : 0, id);
if (!wasRemoved && parent)
parent->RemoveChild(this);
}
void C4MenuWindow::EnableScrollBar(bool enable)
void C4MenuWindow::EnableScrollBar(bool enable, float childrenHeight)
{
const int32_t &style = props[C4MenuWindowPropertyName::style].GetInt();
if (style & C4MenuWindowStyleFlag::FitChildren)
{
float height = lastDrawPosition.bottom - lastDrawPosition.top;
props[C4MenuWindowPropertyName::bottom].current->d += (childrenHeight - height);
return;
}
if (!enable && scrollBar)
{
delete scrollBar; scrollBar = 0;
@ -783,7 +801,7 @@ void C4MenuWindow::EnableScrollBar(bool enable)
void C4MenuWindow::UpdateLayout()
{
LogF("Updating Layout %p, root: %d, main: %d, style: %d", this, int(this == &::MenuWindowRoot), int(isMainWindow), props[C4MenuWindowPropertyName::style].GetInt());
//LogF("Updating Layout %p, root: %d, main: %d, style: %d", this, int(this == &::MenuWindowRoot), int(isMainWindow), props[C4MenuWindowPropertyName::style].GetInt());
const int32_t &style = props[C4MenuWindowPropertyName::style].GetInt();
// update scroll bar according to children
@ -808,40 +826,17 @@ void C4MenuWindow::UpdateLayout()
float height = lastDrawPosition.bottom - lastDrawPosition.top;
float childHgt = lastDrawPosition.bottomMostChild - lastDrawPosition.topMostChild;
if (childHgt > height) // need a scroll bar or adjustment!
{
// adjust size or just use a scroll bar?
if (style & C4MenuWindowStyleFlag::FitChildren)
{
// just overwrite the current active tag
props[C4MenuWindowPropertyName::bottom].current->d += (childHgt - height);
}
else
EnableScrollBar(true);
}
else
{
// revert possible height adjustment?
if (style & C4MenuWindowStyleFlag::FitChildren)
{
// just overwrite the current active tag
props[C4MenuWindowPropertyName::bottom].current->d += (childHgt - height);
}
// deactivate scrollbar always
EnableScrollBar(false);
}
EnableScrollBar(childHgt > height, childHgt);
// special layout selected?
if (style & C4MenuWindowStyleFlag::Grid)
if (style & C4MenuWindowStyleFlag::GridLayout)
UpdateLayoutGrid();
else if (style & C4MenuWindowStyleFlag::Vertical)
else if (style & C4MenuWindowStyleFlag::VerticalLayout)
UpdateLayoutVertical();
}
void C4MenuWindow::UpdateLayoutGrid()
{
Log("Updating grid layout!");
const int32_t width = lastDrawPosition.right - lastDrawPosition.left;
const int32_t height = lastDrawPosition.bottom - lastDrawPosition.top;
@ -882,7 +877,7 @@ void C4MenuWindow::UpdateLayoutGrid()
lastDrawPosition.bottomMostChild = currentY;
// do we need a scroll bar?
EnableScrollBar(currentY >= height);
EnableScrollBar(currentY >= height, currentY);
}
void C4MenuWindow::UpdateLayoutVertical()
@ -913,7 +908,7 @@ void C4MenuWindow::UpdateLayoutVertical()
lastDrawPosition.bottomMostChild = currentY;
// do we need a scroll bar?
EnableScrollBar(currentY >= height);
EnableScrollBar(currentY >= height, currentY);
}
bool C4MenuWindow::DrawChildren(C4TargetFacet &cgo, int32_t player, float parentLeft, float parentTop, float parentRight, float parentBottom, int32_t withMultipleFlag)
@ -961,7 +956,7 @@ bool C4MenuWindow::Draw(C4TargetFacet &cgo, int32_t player)
// rounding against small errors
if ((int(wdt) != int(lastDrawPosition.right)) || (int(hgt) != int(lastDrawPosition.bottom)))
{
LogF("Updating root lastDrawPosition %f|%f // %f|%f", cgo.X, cgo.Y, cgo.Wdt, cgo.Hgt);
//LogF("Updating root lastDrawPosition %f|%f // %f|%f", cgo.X, cgo.Y, cgo.Wdt, cgo.Hgt);
lastDrawPosition.right = wdt;
lastDrawPosition.bottom = hgt;
lastDrawPosition.dirty = 1;
@ -970,7 +965,7 @@ bool C4MenuWindow::Draw(C4TargetFacet &cgo, int32_t player)
lastDrawPosition.dirty = 0;
// step one: draw all non-multiple windows
DrawChildren(cgo, player, leftDrawX, topDrawY, rightDrawX, bottomDrawY, 1);
DrawChildren(cgo, player, leftDrawX - standardHorizontalBorder, topDrawY - standardVerticalBorder, rightDrawX + standardHorizontalBorder, bottomDrawY + standardVerticalBorder, 1);
// TODO: adjust rectangle for main menu if multiple windows exist
// step two: draw one "main" menu
DrawChildren(cgo, player, leftDrawX, topDrawY, rightDrawX, bottomDrawY, 0);
@ -1148,11 +1143,11 @@ void C4MenuWindow::SetTag(C4String *tag)
if (parent)
{
parent->lastDrawPosition.dirty = 2;
LogF("Change tag %d to %s", i, tag->GetCStr());
//LogF("Change tag %d to %s", i, tag->GetCStr());
}
}
if (parent->lastDrawPosition.dirty == 2) Log("Tag change forces update");
// .. and children
for (std::list<C4MenuWindow*>::iterator iter = children.begin(); iter != children.end(); ++iter)
(*iter)->SetTag(tag);
@ -1196,6 +1191,10 @@ bool C4MenuWindow::MouseInput(int32_t player, int32_t button, int32_t mouseX, in
{
if (!visible) return false;
if (target)
if (!target->IsVisible(player, false))
return false;
// we have mouse focus! Is this new?
if (!hasMouseFocus)
OnMouseIn(player);
@ -1206,7 +1205,8 @@ bool C4MenuWindow::MouseInput(int32_t player, int32_t button, int32_t mouseX, in
// children actually have a higher priority
bool overChild = false; // remember for later, catch all actions that are in theory over children, even if not reaction (if main window)
for (std::list<C4MenuWindow*>::iterator iter = children.begin(); iter != children.end(); ++iter)
// use reverse iterator since children with higher Priority appear later in the list
for (std::list<C4MenuWindow*>::reverse_iterator iter = children.rbegin(); iter != children.rend(); ++iter)
{
C4MenuWindow *child = *iter;
int32_t childLeft = static_cast<int32_t>(child->lastDrawPosition.left);
@ -1268,7 +1268,7 @@ bool C4MenuWindow::ExecuteCommand(int32_t actionID, int32_t player, int32_t subw
{
if (isMainWindow && subwindowID) // we are a main window! try a shortcut through the ID?
{
LogF("passing command... %d, %d, %d, %d, %d [I am %d, MW]", actionID, player, subwindowID, actionType, tag, id);
//LogF("passing command... %d, %d, %d, %d, %d [I am %d, MW]", actionID, player, subwindowID, actionType, tag, id);
// the reasoning for that shortcut is that I assume that usually windows with actions will also have an ID assigned
// this obviously doesn't have to be the case, but I believe it's worth the try
std::pair<std::multimap<int32_t, C4MenuWindow*>::iterator, std::multimap<int32_t, C4MenuWindow*>::iterator> range;
@ -1276,7 +1276,6 @@ bool C4MenuWindow::ExecuteCommand(int32_t actionID, int32_t player, int32_t subw
for (std::multimap<int32_t, C4MenuWindow*>::iterator iter = range.first; iter != range.second; ++iter)
{
LogF("iterating.. size %d", childrenIDMap.size());
if (iter->second->ExecuteCommand(actionID, player, subwindowID, actionType, target, tag))
return true;
}
@ -1286,7 +1285,6 @@ bool C4MenuWindow::ExecuteCommand(int32_t actionID, int32_t player, int32_t subw
// are we elligible?
if ((id == subwindowID) && (this->target == target))
{
Log("command target found");
C4MenuWindowAction *action = props[actionType].GetActionForTag(tag);
if (action)
{

View File

@ -45,6 +45,7 @@ enum C4MenuWindowPropertyName
onClickAction,
onMouseInAction,
onMouseOutAction,
onCloseAction,
style,
priority,
_lastProp
@ -59,8 +60,8 @@ enum C4MenuWindowActionID
enum C4MenuWindowStyleFlag
{
None = 0,
Grid = 1,
Vertical = 2,
GridLayout = 1,
VerticalLayout = 2,
TextVCenter = 4,
TextHCenter = 8,
TextRight = 16,
@ -227,7 +228,8 @@ class C4MenuWindow
void UpdateLayout();
void UpdateLayoutGrid();
void UpdateLayoutVertical();
void EnableScrollBar(bool enable = true);
// children height should be set when enabling a scroll bar so that, with style FitChildren, the size can simply be changed
void EnableScrollBar(bool enable = true, float childrenHeight = 0.0f);
public:
// used by mouse input, this is in screen coordinates
@ -260,8 +262,9 @@ class C4MenuWindow
// pass a proplist to create a window + subwindows as specified
// in theory, you could call this function on a window more than once
bool CreateFromPropList(C4PropList *proplist);
// you can call this function on a window more than once
// if isUpdate is true, all new children will have resetStdTag set
bool CreateFromPropList(C4PropList *proplist, bool resetStdTag = false, bool isUpdate = false);
// C4MenuWindow will delete its children on close. Make sure you don't delete anything twice
C4MenuWindow *AddChild(C4MenuWindow *child);

View File

@ -159,6 +159,7 @@ C4StringTable::C4StringTable()
P[P_OnClick] = "OnClick";
P[P_OnMouseIn] = "OnMouseIn";
P[P_OnMouseOut] = "OnMouseOut";
P[P_OnClose] = "OnClose";
P[P_ID] = "ID";
P[P_Style] = "Style";
P[DFA_WALK] = "WALK";

View File

@ -364,6 +364,7 @@ enum C4PropertyName
P_OnClick,
P_OnMouseIn,
P_OnMouseOut,
P_OnClose,
P_Style,
// Default Action Procedures
DFA_WALK,