1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-26 03:52:01 +02:00

Merge pull request #2282 from IvanSavenko/adventure_map_fixes

Adventure map fixes for 1.3
This commit is contained in:
Ivan Savenko 2023-07-07 14:27:58 +03:00 committed by GitHub
commit ae8579558d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 258 additions and 222 deletions

View File

@ -448,6 +448,12 @@ void AIGateway::battleResultsApplied()
status.setBattle(NO_BATTLE);
}
void AIGateway::beforeObjectPropertyChanged(const SetObjectProperty * sop)
{
}
void AIGateway::objectPropertyChanged(const SetObjectProperty * sop)
{
LOG_TRACE(logAi);

View File

@ -161,6 +161,7 @@ public:
void heroManaPointsChanged(const CGHeroInstance * hero) override;
void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;
void battleResultsApplied() override;
void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
void objectPropertyChanged(const SetObjectProperty * sop) override;
void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override;
void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;

View File

@ -538,6 +538,11 @@ void VCAI::battleResultsApplied()
status.setBattle(NO_BATTLE);
}
void VCAI::beforeObjectPropertyChanged(const SetObjectProperty * sop)
{
}
void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
{
LOG_TRACE(logAi);

View File

@ -194,6 +194,7 @@ public:
void heroManaPointsChanged(const CGHeroInstance * hero) override;
void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;
void battleResultsApplied() override;
void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
void objectPropertyChanged(const SetObjectProperty * sop) override;
void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override;
void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;

View File

@ -183,7 +183,10 @@ void CPlayerInterface::playerStartsTurn(PlayerColor player)
if (player != playerID && LOCPLINT == this)
{
waitWhileDialog();
adventureInt->onEnemyTurnStarted(player);
bool isHuman = cb->getStartInfo()->playerInfos.count(player) && cb->getStartInfo()->playerInfos.at(player).isControlledByHuman();
adventureInt->onEnemyTurnStarted(player, isHuman);
}
}
@ -1314,11 +1317,8 @@ void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanc
GH.windows().createAndPushWindow<CExchangeWindow>(hero1, hero2, query);
}
void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
void CPlayerInterface::beforeObjectPropertyChanged(const SetObjectProperty * sop)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
//redraw minimap if owner changed
if (sop->what == ObjProperty::OWNER)
{
const CGObjectInstance * obj = cb->getObj(sop->id);
@ -1328,13 +1328,34 @@ void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
auto town = static_cast<const CGTownInstance *>(obj);
if(obj->tempOwner == playerID)
localState->addOwnedTown(town);
else
{
localState->removeOwnedTown(town);
adventureInt->onTownChanged(town);
}
}
}
}
adventureInt->onTownChanged(town);
void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
if (sop->what == ObjProperty::OWNER)
{
const CGObjectInstance * obj = cb->getObj(sop->id);
if(obj->ID == Obj::TOWN)
{
auto town = static_cast<const CGTownInstance *>(obj);
if(obj->tempOwner == playerID)
{
localState->addOwnedTown(town);
adventureInt->onTownChanged(town);
}
}
//redraw minimap if owner changed
std::set<int3> pos = obj->getBlockedPos();
std::unordered_set<int3> upos(pos.begin(), pos.end());
adventureInt->onMapTilesChanged(upos);

View File

@ -144,6 +144,7 @@ protected: // Call-ins from server, should not be called directly, but only via
void requestRealized(PackageApplied *pa) override;
void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) override;
void centerView (int3 pos, int focusTime) override;
void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
void objectPropertyChanged(const SetObjectProperty * sop) override;
void objectRemoved(const CGObjectInstance *obj) override;
void objectRemovedAfter() override;

View File

@ -128,4 +128,5 @@ public:
virtual void visitBattleStackMoved(BattleStackMoved & pack) override;
virtual void visitBattleAttack(BattleAttack & pack) override;
virtual void visitStartAction(StartAction & pack) override;
};
virtual void visitSetObjectProperty(SetObjectProperty & pack) override;
};

View File

@ -611,6 +611,20 @@ void ApplyClientNetPackVisitor::visitInfoWindow(InfoWindow & pack)
logNetwork->warn("We received InfoWindow for not our player...");
}
void ApplyFirstClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
{
//inform all players that see this object
for(auto it = cl.playerint.cbegin(); it != cl.playerint.cend(); ++it)
{
if(gs.isVisible(gs.getObjInstance(pack.id), it->first))
callInterfaceIfPresent(cl, it->first, &IGameEventsReceiver::beforeObjectPropertyChanged, &pack);
}
// invalidate section of map view with our object and force an update with new flag color
if (pack.what == ObjProperty::OWNER)
CGI->mh->onObjectInstantRemove(gs.getObjInstance(pack.id));
}
void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
{
//inform all players that see this object
@ -620,12 +634,9 @@ void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
callInterfaceIfPresent(cl, it->first, &IGameEventsReceiver::objectPropertyChanged, &pack);
}
// invalidate section of map view with our object and force an update with new flag color
if (pack.what == ObjProperty::OWNER)
{
// invalidate section of map view with our object and force an update with new flag color
CGI->mh->onObjectInstantRemove(gs.getObjInstance(pack.id));
CGI->mh->onObjectInstantAdd(gs.getObjInstance(pack.id));
}
}
void ApplyClientNetPackVisitor::visitHeroLevelUp(HeroLevelUp & pack)

View File

@ -83,8 +83,11 @@ void AdventureMapInterface::onAudioPaused()
void AdventureMapInterface::onHeroMovementStarted(const CGHeroInstance * hero)
{
widget->getInfoBar()->popAll();
widget->getInfoBar()->showSelection();
if (shortcuts->optionMapViewActive())
{
widget->getInfoBar()->popAll();
widget->getInfoBar()->showSelection();
}
}
void AdventureMapInterface::onHeroChanged(const CGHeroInstance *h)
@ -137,6 +140,9 @@ void AdventureMapInterface::deactivate()
{
CIntObject::deactivate();
CCS->curh->set(Cursor::Map::POINTER);
if(LOCPLINT)
LOCPLINT->cingconsole->deactivate();
}
void AdventureMapInterface::showAll(Canvas & to)
@ -309,16 +315,15 @@ void AdventureMapInterface::onHotseatWaitStarted(PlayerColor playerID)
setState(EAdventureState::HOTSEAT_WAIT);
}
void AdventureMapInterface::onEnemyTurnStarted(PlayerColor playerID)
void AdventureMapInterface::onEnemyTurnStarted(PlayerColor playerID, bool isHuman)
{
if(settings["session"]["spectate"].Bool())
return;
mapAudio->onEnemyTurnStarted();
widget->getMinimap()->setAIRadar(true);
widget->getMinimap()->setAIRadar(!isHuman);
widget->getInfoBar()->startEnemyTurn(LOCPLINT->cb->getCurrentPlayer());
setState(EAdventureState::ENEMY_TURN);
}
void AdventureMapInterface::setState(EAdventureState state)
@ -333,17 +338,8 @@ void AdventureMapInterface::adjustActiveness()
bool widgetMustBeActive = isActive() && shortcuts->optionSidePanelActive();
bool mapViewMustBeActive = isActive() && (shortcuts->optionMapViewActive());
if (widgetMustBeActive && !widget->isActive())
widget->activate();
if (!widgetMustBeActive && widget->isActive())
widget->deactivate();
if (mapViewMustBeActive && !widget->getMapView()->isActive())
widget->getMapView()->activate();
if (!mapViewMustBeActive && widget->getMapView()->isActive())
widget->getMapView()->deactivate();
widget->setInputEnabled(widgetMustBeActive);
widget->getMapView()->setInputEnabled(mapViewMustBeActive);
}
void AdventureMapInterface::onCurrentPlayerChanged(PlayerColor playerID)

View File

@ -115,7 +115,7 @@ public:
void onHotseatWaitStarted(PlayerColor playerID);
/// Called by PlayerInterface when AI or remote human player starts his turn
void onEnemyTurnStarted(PlayerColor playerID);
void onEnemyTurnStarted(PlayerColor playerID, bool isHuman);
/// Called by PlayerInterface when local human player starts his turn
void onPlayerTurnStarted(PlayerColor playerID);

View File

@ -402,7 +402,7 @@ bool AdventureMapShortcuts::optionCanViewQuests()
bool AdventureMapShortcuts::optionCanToggleLevel()
{
return optionInMapView() && LOCPLINT->cb->getMapSize().z > 0;
return optionInMapView() && LOCPLINT->cb->getMapSize().z > 1;
}
bool AdventureMapShortcuts::optionMapLevelSurface()

View File

@ -34,7 +34,7 @@ CInGameConsole::CInGameConsole()
: CIntObject(KEYBOARD | TIME | TEXTINPUT)
, prevEntDisp(-1)
{
type |= REDRAW_PARENT;
setRedrawParent(true);
}
void CInGameConsole::showAll(Canvas & to)
@ -96,7 +96,7 @@ void CInGameConsole::print(const std::string & txt)
auto splitText = CMessage::breakText(txt, maxWidth, FONT_MEDIUM);
for (auto const & entry : splitText)
for(const auto & entry : splitText)
texts.push_back({entry, 0});
while(texts.size() > maxDisplayedTexts)
@ -104,6 +104,27 @@ void CInGameConsole::print(const std::string & txt)
}
GH.windows().totalRedraw(); // FIXME: ingame console has no parent widget set
CCS->soundh->playSound("CHAT");
}
bool CInGameConsole::captureThisKey(EShortcut key)
{
if (enteredText.empty())
return false;
switch (key)
{
case EShortcut::GLOBAL_ACCEPT:
case EShortcut::GLOBAL_CANCEL:
case EShortcut::GAME_ACTIVATE_CONSOLE:
case EShortcut::GLOBAL_BACKSPACE:
case EShortcut::MOVE_UP:
case EShortcut::MOVE_DOWN:
return true;
default:
return false;
}
}
void CInGameConsole::keyPressed (EShortcut key)
@ -111,18 +132,18 @@ void CInGameConsole::keyPressed (EShortcut key)
if (LOCPLINT->cingconsole != this)
return;
if(!captureAllKeys && key != EShortcut::GAME_ACTIVATE_CONSOLE)
if(enteredText.empty() && key != EShortcut::GAME_ACTIVATE_CONSOLE)
return; //because user is not entering any text
switch(key)
{
case EShortcut::GLOBAL_CANCEL:
if(captureAllKeys)
if(!enteredText.empty())
endEnteringText(false);
break;
case EShortcut::GAME_ACTIVATE_CONSOLE:
if(captureAllKeys)
if(!enteredText.empty())
endEnteringText(false);
else
startEnteringText();
@ -130,15 +151,10 @@ void CInGameConsole::keyPressed (EShortcut key)
case EShortcut::GLOBAL_ACCEPT:
{
if(!enteredText.empty() && captureAllKeys)
if(!enteredText.empty())
{
bool anyTextExceptCaret = enteredText.size() > 1;
endEnteringText(anyTextExceptCaret);
if(anyTextExceptCaret)
{
CCS->soundh->playSound("CHAT");
}
}
break;
}
@ -195,8 +211,9 @@ void CInGameConsole::textInputed(const std::string & inputtedText)
if (LOCPLINT->cingconsole != this)
return;
if(!captureAllKeys || enteredText.empty())
if(enteredText.empty())
return;
enteredText.resize(enteredText.size()-1);
enteredText += inputtedText;
@ -215,14 +232,10 @@ void CInGameConsole::startEnteringText()
if (!isActive())
return;
if (captureAllKeys)
return;
assert(currentStatusBar.expired());//effectively, nullptr check
currentStatusBar = GH.statusbar();
captureAllKeys = true;
enteredText = "_";
GH.statusbar()->setEnteringMode(true);
@ -231,7 +244,6 @@ void CInGameConsole::startEnteringText()
void CInGameConsole::endEnteringText(bool processEnteredText)
{
captureAllKeys = false;
prevEntDisp = -1;
if(processEnteredText)
{

View File

@ -50,6 +50,7 @@ public:
void keyPressed(EShortcut key) override;
void textInputed(const std::string & enteredText) override;
void textEdited(const std::string & enteredText) override;
bool captureThisKey(EShortcut key) override;
void startEnteringText();
void endEnteringText(bool processEnteredText);

View File

@ -231,7 +231,7 @@ void CMinimap::setAIRadar(bool on)
redraw();
}
void CMinimap::updateTiles(std::unordered_set<int3> positions)
void CMinimap::updateTiles(const std::unordered_set<int3> & positions)
{
if(minimap)
{

View File

@ -68,6 +68,6 @@ public:
void showAll(Canvas & to) override;
void updateTiles(std::unordered_set<int3> positions);
void updateTiles(const std::unordered_set<int3> & positions);
};

View File

@ -33,6 +33,12 @@ void InputSourceKeyboard::handleEventKeyDown(const SDL_KeyboardEvent & key)
if(key.repeat != 0)
return; // ignore periodic event resends
if (SDL_IsTextInputActive() == SDL_TRUE)
{
if (key.keysym.sym >= ' ' && key.keysym.sym < 0x80)
return; // printable character - will be handled as text input
}
assert(key.state == SDL_PRESSED);
if(key.keysym.sym >= SDLK_F1 && key.keysym.sym <= SDLK_F15 && settings["session"]["spectate"].Bool())
@ -77,6 +83,12 @@ void InputSourceKeyboard::handleEventKeyUp(const SDL_KeyboardEvent & key)
if(key.repeat != 0)
return; // ignore periodic event resends
if (SDL_IsTextInputActive() == SDL_TRUE)
{
if (key.keysym.sym >= ' ' && key.keysym.sym < 0x80)
return; // printable character - will be handled as text input
}
assert(key.state == SDL_RELEASED);
auto shortcutsVector = GH.shortcuts().translateKeycode(key.keysym.sym);

View File

@ -18,6 +18,12 @@
#include "../gui/MouseButton.h"
#include <SDL_events.h>
#include <SDL_hints.h>
InputSourceMouse::InputSourceMouse()
{
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
}
void InputSourceMouse::handleEventMouseMotion(const SDL_MouseMotionEvent & motion)
{

View File

@ -24,6 +24,8 @@ class InputSourceMouse
Point middleClickPosition;
int mouseButtonsMask = 0;
public:
InputSourceMouse();
void handleEventMouseMotion(const SDL_MouseMotionEvent & current);
void handleEventMouseButtonDown(const SDL_MouseButtonEvent & current);
void handleEventMouseWheel(const SDL_MouseWheelEvent & current);

View File

@ -12,6 +12,7 @@
#include "CGuiHandler.h"
#include "WindowHandler.h"
#include "EventDispatcher.h"
#include "Shortcut.h"
#include "../render/Canvas.h"
#include "../windows/CMessage.h"
@ -20,18 +21,13 @@
CIntObject::CIntObject(int used_, Point pos_):
parent_m(nullptr),
parent(parent_m),
type(0)
redrawParent(false),
inputEnabled(true),
used(used_),
recActions(GH.defActionsDef),
defActions(GH.defActionsDef),
pos(pos_, Point())
{
captureAllKeys = false;
used = used_;
recActions = defActions = GH.defActionsDef;
pos.x = pos_.x;
pos.y = pos_.y;
pos.w = 0;
pos.h = 0;
if(GH.captureChildren)
GH.createdObj.front()->addChild(this, true);
}
@ -76,7 +72,11 @@ void CIntObject::activate()
if (isActive())
return;
activateEvents(used | GENERAL);
if (inputEnabled)
activateEvents(used | GENERAL);
else
activateEvents(GENERAL);
assert(isActive());
if(defActions & ACTIVATE)
@ -102,7 +102,7 @@ void CIntObject::deactivate()
void CIntObject::addUsedEvents(ui16 newActions)
{
if (isActive())
if (isActive() && inputEnabled)
activateEvents(~used & newActions);
used |= newActions;
}
@ -141,6 +141,32 @@ void CIntObject::setEnabled(bool on)
disable();
}
void CIntObject::setInputEnabled(bool on)
{
if (inputEnabled == on)
return;
inputEnabled = on;
if (isActive())
{
assert((used & GENERAL) == 0);
if (on)
activateEvents(used);
else
deactivateEvents(used);
}
for(auto & elem : children)
elem->setInputEnabled(on);
}
void CIntObject::setRedrawParent(bool on)
{
redrawParent = on;
}
void CIntObject::fitToScreen(int borderWidth, bool propagate)
{
Point newPos = pos.topLeft();
@ -181,6 +207,9 @@ void CIntObject::addChild(CIntObject * child, bool adjustPosition)
if(adjustPosition)
child->moveBy(pos.topLeft(), adjustPosition);
if (inputEnabled != child->inputEnabled)
child->setInputEnabled(inputEnabled);
if (!isActive() && child->isActive())
child->deactivate();
if (isActive()&& !child->isActive())
@ -210,7 +239,7 @@ void CIntObject::redraw()
//it should fix glitches when called by inactive elements located below active window
if (isActive())
{
if (parent_m && (type & REDRAW_PARENT))
if (parent_m && redrawParent)
{
parent_m->redraw();
}
@ -266,7 +295,7 @@ const Rect & CIntObject::center(const Point & p, bool propagate)
bool CIntObject::captureThisKey(EShortcut key)
{
return captureAllKeys;
return false;
}
CKeyShortcut::CKeyShortcut()

View File

@ -47,11 +47,10 @@ class CIntObject : public IShowActivatable, public AEventsReceiver //interface o
//non-const versions of fields to allow changing them in CIntObject
CIntObject *parent_m; //parent object
public:
//redraw parent flag - this int may be semi-transparent and require redraw of parent window
enum {REDRAW_PARENT=8};
int type; //bin flags using etype
bool inputEnabled;
bool redrawParent;
public:
std::vector<CIntObject *> children;
/// read-only parent access. May not be a "clean" solution but allows some compatibility
@ -63,10 +62,8 @@ public:
CIntObject(int used=0, Point offset=Point());
virtual ~CIntObject();
//keyboard handling
bool captureAllKeys; //if true, only this object should get info about pressed keys
bool captureThisKey(EShortcut key) override; //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
/// allows capturing key input so it will be delivered only to this element
bool captureThisKey(EShortcut key) override;
void addUsedEvents(ui16 newActions);
void removeUsedEvents(ui16 newActions);
@ -82,6 +79,13 @@ public:
/// deactivates or activates UI element based on flag
void setEnabled(bool on);
/// Block (or allow) all user input, e.g. mouse/keyboard/touch without hiding element
void setInputEnabled(bool on);
/// Mark this input as one that requires parent redraw on update,
/// for example if current control might have semi-transparent elements and requires redrawing of background
void setRedrawParent(bool on);
// activate or deactivate object. Inactive object won't receive any input events (keyboard\mouse)
// usually used automatically by parent
void activate() override;

View File

@ -63,7 +63,9 @@ void EventDispatcher::dispatchTimer(uint32_t msPassed)
EventReceiversList hlp = timeinterested;
for (auto & elem : hlp)
{
if(!vstd::contains(timeinterested,elem)) continue;
if(!vstd::contains(timeinterested,elem))
continue;
elem->tick(msPassed);
}
}

View File

@ -493,7 +493,7 @@ public:
InterfaceLayoutWidget::InterfaceLayoutWidget()
:CIntObject()
{
type |= REDRAW_PARENT;
setRedrawParent(true);
}
std::shared_ptr<CIntObject> InterfaceObjectConfigurable::buildLayout(const JsonNode & config)

View File

@ -28,98 +28,14 @@
@implementation SDLViewObserver
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
[object removeObserver:self forKeyPath:keyPath];
UIView * view = [object valueForKeyPath:keyPath];
auto longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
longPress.minimumPressDuration = 0.2;
[view addGestureRecognizer:longPress];
auto pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
[view addGestureRecognizer:pinch];
}
#pragma mark - Gestures
- (void)handleLongPress:(UIGestureRecognizer *)gesture {
// send RMB click
SDL_EventType mouseButtonType;
switch (gesture.state)
{
case UIGestureRecognizerStateBegan:
mouseButtonType = SDL_MOUSEBUTTONDOWN;
break;
case UIGestureRecognizerStateEnded:
mouseButtonType = SDL_MOUSEBUTTONUP;
break;
default:
return;
}
auto renderer = SDL_GetRenderer(mainWindow);
float scaleX, scaleY;
SDL_Rect viewport;
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
SDL_RenderGetViewport(renderer, &viewport);
auto touchedPoint = [gesture locationInView:gesture.view];
auto screenScale = UIScreen.mainScreen.nativeScale;
Sint32 x = (int)touchedPoint.x * screenScale / scaleX - viewport.x;
Sint32 y = (int)touchedPoint.y * screenScale / scaleY - viewport.y;
SDL_Event rmbEvent;
rmbEvent.button = (SDL_MouseButtonEvent){
.type = mouseButtonType,
.button = SDL_BUTTON_RIGHT,
.clicks = 1,
.x = x,
.y = y,
};
SDL_PushEvent(&rmbEvent);
// small hack to prevent cursor jumping
if (mouseButtonType == SDL_MOUSEBUTTONUP)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.025 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
SDL_Event motionEvent;
motionEvent.motion = (SDL_MouseMotionEvent){
.type = SDL_MOUSEMOTION,
.x = x,
.y = y,
};
SDL_PushEvent(&motionEvent);
});
}
- (void)handlePinch:(UIGestureRecognizer *)gesture {
if(gesture.state != UIGestureRecognizerStateBegan || CSH->state != EClientState::GAMEPLAY)
return;
[GameChatKeyboardHandler sendKeyEventWithKeyCode:SDLK_SPACE];
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return [gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]];
}
@end
int startSDL(int argc, char * argv[], BOOL startManually)
{
@autoreleasepool {
auto observer = [SDLViewObserver new];
observer.gameChatHandler = [GameChatKeyboardHandler new];
id __block sdlWindowCreationObserver = [NSNotificationCenter.defaultCenter addObserverForName:UIWindowDidBecomeKeyNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
[NSNotificationCenter.defaultCenter removeObserver:sdlWindowCreationObserver];
sdlWindowCreationObserver = nil;
UIWindow * sdlWindow = note.object;
[sdlWindow.rootViewController addObserver:observer forKeyPath:NSStringFromSelector(@selector(view)) options:NSKeyValueObservingOptionNew context:NULL];
}];
id textFieldObserver = [NSNotificationCenter.defaultCenter addObserverForName:UITextFieldTextDidEndEditingNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
removeFocusFromActiveInput();
}];

View File

@ -115,7 +115,7 @@ InfoCard::InfoCard()
: showChat(true)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
CIntObject::type |= REDRAW_PARENT;
setRedrawParent(true);
pos.x += 393;
pos.y += 6;
@ -310,8 +310,7 @@ CChatBox::CChatBox(const Rect & rect)
{
OBJ_CONSTRUCTION;
pos += rect.topLeft();
captureAllKeys = true;
type |= REDRAW_PARENT;
setRedrawParent(true);
const int height = static_cast<int>(graphics->fonts[FONT_SMALL]->getLineHeight());
inputBox = std::make_shared<CTextInput>(Rect(0, rect.h - height, rect.w, height), EFonts::FONT_SMALL, 0);

View File

@ -371,7 +371,7 @@ TemplatesDropBox::ListItem::ListItem(const JsonNode & config, TemplatesDropBox &
pos.w = w->pos.w;
pos.h = w->pos.h;
}
type |= REDRAW_PARENT;
setRedrawParent(true);
}
void TemplatesDropBox::ListItem::updateItem(int idx, const CRmgTemplate * _item)

View File

@ -179,7 +179,7 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
break;
case ESelectionScreen::campaignList:
tabTitle = CGI->generaltexth->allTexts[726];
type |= REDRAW_PARENT; // we use parent background so we need to make sure it's will be redrawn too
setRedrawParent(true); // we use parent background so we need to make sure it's will be redrawn too
pos.w = parent->pos.w;
pos.h = parent->pos.h;
pos.x += 3;
@ -457,10 +457,21 @@ void SelectionTab::updateListItems()
}
}
int SelectionTab::getLine()
bool SelectionTab::receiveEvent(const Point & position, int eventType) const
{
// FIXME: widget should instead have well-defined pos so events will be filtered using standard routine
return getLine(position - pos.topLeft()) != -1;
}
int SelectionTab::getLine() const
{
Point clickPos = GH.getCursorPosition() - pos.topLeft();
return getLine(clickPos);
}
int SelectionTab::getLine(const Point & clickPos) const
{
int line = -1;
Point clickPos = GH.getCursorPosition() - pos.topLeft();
// Ignore clicks on save name area
int maxPosY;

View File

@ -67,8 +67,8 @@ public:
void clickLeft(tribool down, bool previousState) override;
void keyPressed(EShortcut key) override;
void clickDouble() override;
bool receiveEvent(const Point & position, int eventType) const override;
void filter(int size, bool selectFirst = false); //0 - all
void sortBy(int criteria);
@ -77,7 +77,8 @@ public:
void selectAbs(int position); //position: absolute position in curItems vector
void sliderMove(int slidPos);
void updateListItems();
int getLine();
int getLine() const;
int getLine(const Point & position) const;
void selectFileName(std::string fname);
std::shared_ptr<CMapInfo> getSelectedMapInfo() const;
void rememberCurrentSelection();

View File

@ -95,7 +95,7 @@ CMenuScreen::CMenuScreen(const JsonNode & configNode)
menuNameToEntry.push_back("credits");
tabs = std::make_shared<CTabbedInt>(std::bind(&CMenuScreen::createTab, this, _1));
tabs->type |= REDRAW_PARENT;
tabs->setRedrawParent(true);
}
std::shared_ptr<CIntObject> CMenuScreen::createTab(size_t index)
@ -248,7 +248,7 @@ std::shared_ptr<CButton> CMenuEntry::createButton(CMenuScreen * parent, const Js
CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
type |= REDRAW_PARENT;
setRedrawParent(true);
pos = parent->pos;
for(const JsonNode & node : config["images"].Vector())
@ -258,7 +258,7 @@ CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
{
buttons.push_back(createButton(parent, node));
buttons.back()->hoverable = true;
buttons.back()->type |= REDRAW_PARENT;
buttons.back()->setRedrawParent(true);
}
}

View File

@ -24,7 +24,7 @@ CreditsScreen::CreditsScreen(Rect rect)
{
pos.w = rect.w;
pos.h = rect.h;
type |= REDRAW_PARENT;
setRedrawParent(true);
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
auto textFile = CResourceHandler::get()->load(ResourceID("DATA/CREDITS.TXT"))->readAll();
std::string text((char *)textFile.first.get(), textFile.second);

View File

@ -90,7 +90,6 @@ void MapView::show(Canvas & to)
MapView::MapView(const Point & offset, const Point & dimensions)
: BasicMapView(offset, dimensions)
, isSwiping(false)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
actions = std::make_shared<MapViewActions>(*this, model);
@ -110,21 +109,15 @@ void MapView::onMapLevelSwitched()
void MapView::onMapScrolled(const Point & distance)
{
if(!isSwiping)
if(!isGesturing())
controller->setViewCenter(model->getMapViewCenter() + distance, model->getLevel());
}
void MapView::onMapSwiped(const Point & viewPosition)
{
isSwiping = true;
controller->setViewCenter(model->getMapViewCenter() + viewPosition, model->getLevel());
}
void MapView::onMapSwipeEnded()
{
isSwiping = false;
}
void MapView::onCenteredTile(const int3 & tile)
{
controller->setViewCenter(tile);

View File

@ -48,8 +48,6 @@ class MapView : public BasicMapView
{
std::shared_ptr<MapViewActions> actions;
bool isSwiping;
public:
void show(Canvas & to) override;
@ -64,9 +62,6 @@ public:
/// Moves current view to specified position, in pixels
void onMapSwiped(const Point & viewPosition);
/// Ends swiping mode and allows normal map scrolling once again
void onMapSwipeEnded();
/// Moves current view to specified tile
void onCenteredTile(const int3 & tile);

View File

@ -185,9 +185,16 @@ void MapViewController::tick(uint32_t timeDelta)
fadingInContext->progress = std::min( 1.0, fadingInContext->progress);
}
if (adventureContext)
adventureContext->animationTime += timeDelta;
updateState();
}
void MapViewController::updateState()
{
if(adventureContext)
{
adventureContext->animationTime += timeDelta;
adventureContext->settingsSessionSpectate = settings["session"]["spectate"].Bool();
adventureContext->settingsAdventureObjectAnimation = settings["adventure"]["objectAnimation"].Bool();
adventureContext->settingsAdventureTerrainAnimation = settings["adventure"]["terrainAnimation"].Bool();
@ -511,6 +518,7 @@ void MapViewController::activateAdventureContext(uint32_t animationTime)
adventureContext = std::make_shared<MapRendererAdventureContext>(*state);
adventureContext->animationTime = animationTime;
context = adventureContext;
updateState();
}
void MapViewController::activateAdventureContext()

View File

@ -74,6 +74,7 @@ private:
void onAfterHeroDisembark(const CGHeroInstance * obj, const int3 & from, const int3 & dest) override;
void resetContext();
void updateState();
public:
MapViewController(std::shared_ptr<MapViewModel> model, std::shared_ptr<MapViewCache> view);

View File

@ -281,7 +281,7 @@ void CSelectableComponent::init()
CSelectableComponent::CSelectableComponent(const Component &c, std::function<void()> OnSelect):
CComponent(c),onSelect(OnSelect)
{
type |= REDRAW_PARENT;
setRedrawParent(true);
addUsedEvents(LCLICK | KEYBOARD);
init();
}
@ -289,7 +289,7 @@ CSelectableComponent::CSelectableComponent(const Component &c, std::function<voi
CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize, std::function<void()> OnSelect):
CComponent(Type,Sub,Val, imageSize),onSelect(OnSelect)
{
type |= REDRAW_PARENT;
setRedrawParent(true);
addUsedEvents(LCLICK | KEYBOARD);
init();
}
@ -466,7 +466,7 @@ CComponentBox::CComponentBox(std::vector<std::shared_ptr<CComponent>> _component
betweenRows(betweenRows),
componentsInRow(componentsInRow)
{
type |= REDRAW_PARENT;
setRedrawParent(true);
pos = position + pos.topLeft();
placeComponents(false);
}
@ -484,7 +484,7 @@ CComponentBox::CComponentBox(std::vector<std::shared_ptr<CSelectableComponent>>
betweenRows(betweenRows),
componentsInRow(componentsInRow)
{
type |= REDRAW_PARENT;
setRedrawParent(true);
pos = position + pos.topLeft();
placeComponents(true);

View File

@ -17,7 +17,7 @@ CreatureCostBox::CreatureCostBox(Rect position, std::string titleText)
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
type |= REDRAW_PARENT;
setRedrawParent(true);
pos = position + pos.topLeft();
title = std::make_shared<CLabel>(pos.w/2, 10, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, titleText);

View File

@ -143,6 +143,7 @@ public:
class LRClickableAreaWTextComp: public LRClickableAreaWText
{
public:
int type;
int baseType;
int bonusValue;
virtual void clickLeft(tribool down, bool previousState) override;

View File

@ -138,6 +138,9 @@ void CListBox::reset()
void CListBox::resize(size_t newSize)
{
if (totalSize == newSize)
return;
totalSize = newSize;
if (slider)
slider->setAmount((int)totalSize);

View File

@ -138,6 +138,10 @@ void CSlider::clickLeft(tribool down, bool previousState)
rw = pw / (pos.h-48);
}
// click on area covered by buttons -> ignore, will be handled by left/right buttons
if (!vstd::iswithin(rw, 0, 1))
return;
slider->clickLeft(true, slider->isMouseLeftButtonPressed());
scrollTo((int)(rw * positions + 0.5));
return;
@ -214,6 +218,10 @@ CSlider::CSlider(Point position, int totalw, std::function<void(int)> Moved, int
pos.h = totalw;
}
// for horizontal sliders that act as values selection - add keyboard event to receive left/right click
if (getOrientation() == Orientation::HORIZONTAL)
addUsedEvents(KEYBOARD);
updateSliderPos();
}

View File

@ -47,7 +47,7 @@ void CLabel::showAll(Canvas & to)
CLabel::CLabel(int x, int y, EFonts Font, ETextAlignment Align, const SDL_Color & Color, const std::string & Text)
: CTextContainer(Align, Font, Color), text(Text)
{
type |= REDRAW_PARENT;
setRedrawParent(true);
autoRedraw = true;
pos.x += x;
pos.y += y;
@ -299,7 +299,7 @@ CTextBox::CTextBox(std::string Text, const Rect & rect, int SliderStyle, EFonts
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
label = std::make_shared<CMultiLineLabel>(rect, Font, Align, Color);
type |= REDRAW_PARENT;
setRedrawParent(true);
pos.x += rect.x;
pos.y += rect.y;
pos.h = rect.h;
@ -492,10 +492,9 @@ CTextInput::CTextInput(const Rect & Pos, EFonts font, const CFunctionList<void(c
cb(CB),
CFocusable(std::make_shared<CKeyboardFocusListener>(this))
{
type |= REDRAW_PARENT;
setRedrawParent(true);
pos.h = Pos.h;
pos.w = Pos.w;
captureAllKeys = true;
background.reset();
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
@ -511,7 +510,6 @@ CTextInput::CTextInput(const Rect & Pos, const Point & bgOffset, const std::stri
pos.h = Pos.h;
pos.w = Pos.w;
captureAllKeys = true;
OBJ_CONSTRUCTION;
background = std::make_shared<CPicture>(bgName, bgOffset.x, bgOffset.y);
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
@ -525,7 +523,6 @@ CTextInput::CTextInput(const Rect & Pos, std::shared_ptr<IImage> srf)
:CFocusable(std::make_shared<CKeyboardFocusListener>(this))
{
pos += Pos.topLeft();
captureAllKeys = true;
OBJ_CONSTRUCTION;
background = std::make_shared<CPicture>(srf, Pos);
pos.w = background->pos.w;
@ -620,17 +617,6 @@ void CTextInput::setText(const std::string & nText, bool callCb)
cb(text);
}
bool CTextInput::captureThisKey(EShortcut key)
{
if(key == EShortcut::GLOBAL_RETURN)
return false;
if (!focus)
return false;
return true;
}
void CTextInput::textInputed(const std::string & enteredText)
{
if(!focus)

View File

@ -227,7 +227,7 @@ public:
void clickLeft(tribool down, bool previousState) override;
void keyPressed(EShortcut key) override;
bool captureThisKey(EShortcut key) override;
//bool captureThisKey(EShortcut key) override;
void textInputed(const std::string & enteredText) override;
void textEdited(const std::string & enteredText) override;

View File

@ -1160,7 +1160,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
updateShadow();
garr = std::make_shared<CGarrisonInt>(305, 387, 4, Point(0,96), town->getUpperArmy(), town->visitingHero);
garr->type |= REDRAW_PARENT;
garr->setRedrawParent(true);
heroes = std::make_shared<HeroSlots>(town, Point(241, 387), Point(241, 483), garr, true);
title = std::make_shared<CLabel>(85, 387, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE, town->getNameTranslated());

View File

@ -1776,7 +1776,7 @@ CObjectListWindow::CItem::CItem(CObjectListWindow * _parent, size_t _id, std::st
border = std::make_shared<CPicture>("TPGATES");
pos = border->pos;
type |= REDRAW_PARENT;
setRedrawParent(true);
text = std::make_shared<CLabel>(pos.w/2, pos.h/2, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, _text);
select(index == parent->selected);
@ -1850,7 +1850,7 @@ void CObjectListWindow::init(std::shared_ptr<CIntObject> titleWidget_, std::stri
}
list = std::make_shared<CListBox>(std::bind(&CObjectListWindow::genItem, this, _1),
Point(14, 151), Point(0, 25), 9, items.size(), 0, 1, Rect(262, -32, 256, 256) );
list->type |= REDRAW_PARENT;
list->setRedrawParent(true);
ok = std::make_shared<CButton>(Point(15, 402), "IOKAY.DEF", CButton::tooltip(), std::bind(&CObjectListWindow::elementSelected, this), EShortcut::GLOBAL_ACCEPT);
ok->block(!list->size());

View File

@ -34,7 +34,7 @@ AdventureOptionsTab::AdventureOptionsTab()
: InterfaceObjectConfigurable()
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
type |= REDRAW_PARENT;
setRedrawParent(true);
const JsonNode config(ResourceID("config/widgets/settings/adventureOptionsTab.json"));
addCallback("playerHeroSpeedChanged", [this](int value)

View File

@ -21,7 +21,7 @@
BattleOptionsTab::BattleOptionsTab(BattleInterface * owner)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
type |= REDRAW_PARENT;
setRedrawParent(true);
const JsonNode config(ResourceID("config/widgets/settings/battleOptionsTab.json"));
addCallback("viewGridChanged", [this, owner](bool value)

View File

@ -94,7 +94,7 @@ GeneralOptionsTab::GeneralOptionsTab()
onFullscreenChanged(settings.listen["video"]["fullscreen"])
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
type |= REDRAW_PARENT;
setRedrawParent(true);
addConditional("touchscreen", GH.input().hasTouchInputDevice());
#ifdef VCMI_MOBILE

View File

@ -71,7 +71,7 @@ SettingsMainWindow::SettingsMainWindow(BattleInterface * parentBattleUi) : Inter
parentBattleInterface = parentBattleUi;
tabContentArea = std::make_shared<CTabbedInt>(std::bind(&SettingsMainWindow::createTab, this, _1), Point(0, 0), defaultTabIndex);
tabContentArea->type |= REDRAW_PARENT;
tabContentArea->setRedrawParent(true);
std::shared_ptr<CToggleGroup> mainTabs = widget<CToggleGroup>("settingsTabs");
mainTabs->setSelected(defaultTabIndex);

View File

@ -127,6 +127,7 @@ public:
virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void requestSent(const CPackForServer *pack, int requestID){};
virtual void requestRealized(PackageApplied *pa){};
virtual void beforeObjectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
virtual void objectRemoved(const CGObjectInstance *obj){}; //eg. collected resource, picked artifact, beaten hero
virtual void objectRemovedAfter(){}; //eg. collected resource, picked artifact, beaten hero

View File

@ -4980,12 +4980,6 @@ void CGameHandler::playerMessage(PlayerColor player, const std::string &message,
{
bool cheated = false;
if(!getPlayerSettings(player)->isControlledByAI())
{
PlayerMessageClient temp_message(player, message);
sendAndApply(&temp_message);
}
std::vector<std::string> words;
boost::split(words, message, boost::is_any_of(" "));
@ -5106,6 +5100,14 @@ void CGameHandler::playerMessage(PlayerColor player, const std::string &message,
if(!player.isSpectator())
checkVictoryLossConditionsForPlayer(player);//Player enter win code or got required art\creature
}
else
{
if(!getPlayerSettings(player)->isControlledByAI())
{
PlayerMessageClient temp_message(player, message);
sendAndApply(&temp_message);
}
}
}
bool CGameHandler::makeCustomAction(BattleAction & ba)