Skip to content

Commit

Permalink
Merge pull request #1499 from Flamefire/windowCloseBehavior
Browse files Browse the repository at this point in the history
Use a 3-state enum for the window close behavior
  • Loading branch information
Flamefire authored Feb 18, 2022
2 parents 3d90130 + cee5dd5 commit 397f2b2
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 123 deletions.
2 changes: 1 addition & 1 deletion external/turtle
Submodule turtle updated 40 files
+13 −20 .github/workflows/ci.yml
+1 −0 doc/changelog.qbk
+0 −18 doc/customization.qbk
+0 −6 doc/example/customization.cpp
+2 −5 doc/reference.qbk
+0 −8 include/turtle/config.hpp
+2 −109 include/turtle/constraint.hpp
+0 −1 include/turtle/constraints.hpp
+21 −18 include/turtle/detail/action.hpp
+183 −0 include/turtle/detail/expectation.hpp
+0 −201 include/turtle/detail/expectation_template.hpp
+46 −62 include/turtle/detail/function.hpp
+120 −43 include/turtle/detail/function_impl.hpp
+0 −11 include/turtle/detail/function_iterate.hpp
+0 −75 include/turtle/detail/function_template.hpp
+13 −4 include/turtle/detail/functor.hpp
+9 −8 include/turtle/detail/matcher_base.hpp
+0 −19 include/turtle/detail/move_helper.hpp
+22 −0 include/turtle/detail/ref_arg.hpp
+3 −3 include/turtle/detail/signature_traits.hpp
+2 −3 include/turtle/detail/type_name.hpp
+3 −9 include/turtle/matcher.hpp
+2 −3 test/CMakeLists.txt
+0 −1 test/Jamfile.jam
+0 −15 test/bench_0_class_10_max_args.cpp
+0 −15 test/bench_0_class_20_max_args.cpp
+0 −15 test/bench_0_class_30_max_args.cpp
+0 −1 test/bench_30_classes_30_methods_30_args.cpp
+0 −1,078 test/bench_30_classes_30_methods_9_args_10_max_args.cpp
+0 −1,078 test/bench_30_classes_30_methods_9_args_20_max_args.cpp
+0 −1,078 test/bench_30_classes_30_methods_9_args_30_max_args.cpp
+48 −4 test/detail/test_function.cpp
+81 −37 test/detail/test_invocation.cpp
+0 −24 test/fail_number_of_arguments_greater_than_max_constant.cpp
+27 −4 test/test_constraint.cpp
+22 −5 test/test_integration.cpp
+31 −41 test/test_log.cpp
+51 −1 test/test_matcher.cpp
+9 −7 test/test_max_args.cpp
+7 −2 test/test_sequence.cpp
6 changes: 3 additions & 3 deletions libs/s25main/WindowManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ void WindowManager::RelayKeyboardMessage(KeyboardMsgHandler msg, const KeyEvent&
// Find one which isn't yet marked for closing so multiple ESC in between draw calls can close multiple windows
const auto itActiveWnd =
std::find_if(windows.rbegin(), windows.rend(), [](const auto& wnd) { return !wnd->ShouldBeClosed(); });
if(itActiveWnd != windows.rend() && (*itActiveWnd)->isUserClosable())
if(itActiveWnd != windows.rend() && (*itActiveWnd)->getCloseBehavior() != CloseBehavior::Custom)
(*itActiveWnd)->Close();
} else if(!CALL_MEMBER_FN(*windows.back(), msg)(ke)) // send to active window
{
Expand Down Expand Up @@ -404,7 +404,7 @@ void WindowManager::Msg_RightDown(const MouseCoords& mc)
if(!curDesktop)
return;

// Sind Fenster vorhanden && ist das aktive Fenster ok
// Right-click closes (most) windows, so check that
if(!windows.empty())
{
IngameWindow* foundWindow = FindWindowAtPos(mc.GetPos());
Expand All @@ -419,7 +419,7 @@ void WindowManager::Msg_RightDown(const MouseCoords& mc)
if(foundWindow)
{
// Close it if requested
if(foundWindow->isUserClosable())
if(foundWindow->getCloseBehavior() == CloseBehavior::Regular)
foundWindow->Close();
else
{
Expand Down
158 changes: 74 additions & 84 deletions libs/s25main/ingameWindows/IngameWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ const DrawPoint IngameWindow::posAtMouse(std::numeric_limits<DrawPoint::ElementT

const Extent IngameWindow::borderSize(1, 1);
IngameWindow::IngameWindow(unsigned id, const DrawPoint& pos, const Extent& size, std::string title,
glArchivItem_Bitmap* background, bool modal, bool isUserClosable, Window* parent)
glArchivItem_Bitmap* background, bool modal, CloseBehavior closeBehavior, Window* parent)
: Window(parent, id, pos, size), title_(std::move(title)), background(background), lastMousePos(0, 0),
last_down(false), last_down2(false), isModal_(modal), closeme(false), isMinimized_(false), isMoving(false),
isUserClosable_(isUserClosable)
closeBehavior_(closeBehavior)
{
std::fill(button_state.begin(), button_state.end(), ButtonState::Up);
std::fill(buttonState.begin(), buttonState.end(), ButtonState::Up);
contentOffset.x = LOADER.GetImageN("resource", 38)->getWidth(); // left border
contentOffset.y = LOADER.GetImageN("resource", 42)->getHeight(); // title bar
contentOffsetEnd.x = LOADER.GetImageN("resource", 39)->getWidth(); // right border
Expand Down Expand Up @@ -142,37 +142,43 @@ void IngameWindow::MouseLeftDown(const MouseCoords& mc)

if(IsPointInRect(mc.GetPos(), title_rect))
{
// Start mit Bewegung
// start moving
isMoving = true;
lastMousePos = mc.GetPos();
}

// beiden Buttons oben links und rechts prfen
const std::array<Rect, 2> rec = {GetLeftButtonRect(), GetRightButtonRect()};

for(unsigned char i = 0; i < 2; ++i)
} else
{
if(IsPointInRect(mc.GetPos(), rec[i]))
button_state[i] = ButtonState::Pressed;
// Check the 2 buttons
const std::array<Rect, 2> rec = {GetCloseButtonBounds(), GetMinimizeButtonBounds()};

for(unsigned i = 0; i < 2; ++i)
{
if(IsPointInRect(mc.GetPos(), rec[i]))
buttonState[i] = ButtonState::Pressed;
}
}
}

void IngameWindow::MouseLeftUp(const MouseCoords& mc)
{
// Bewegung stoppen
isMoving = false;

// beiden Buttons oben links und rechts prfen
const std::array<Rect, 2> rec = {GetLeftButtonRect(), GetRightButtonRect()};
const std::array<Rect, 2> rec = {GetCloseButtonBounds(), GetMinimizeButtonBounds()};

for(unsigned i = 0; i < 2; ++i)
{
button_state[i] = ButtonState::Up;
buttonState[i] = ButtonState::Up;

if((i == 0 && closeBehavior_ == CloseBehavior::Custom) // no close button
|| (i == 1 && isModal_)) // modal windows cannot be minimized
{
continue;
}

if(IsPointInRect(mc.GetPos(), rec[i]))
{
if(i == 0 && isUserClosable_)
if(i == 0)
Close();
else if(i == 1 && !IsModal())
else
{
SetMinimized(!IsMinimized());
LOADER.GetSoundN("sound", 113)->Play(255, false);
Expand All @@ -196,21 +202,18 @@ void IngameWindow::MouseMove(const MouseCoords& mc)

SetPos(newPosBounded);
lastMousePos = mc.GetPos();
}

// beiden Buttons oben links und rechts prfen
const std::array<Rect, 2> rec = {GetLeftButtonRect(), GetRightButtonRect()};

for(unsigned char i = 0; i < 2; ++i)
} else
{
if(IsPointInRect(mc.GetPos(), rec[i]))
// Check the 2 buttons
const std::array<Rect, 2> rec = {GetCloseButtonBounds(), GetMinimizeButtonBounds()};

for(unsigned i = 0; i < 2; ++i)
{
if(mc.ldown)
button_state[i] = ButtonState::Pressed;
if(IsPointInRect(mc.GetPos(), rec[i]))
buttonState[i] = mc.ldown ? ButtonState::Pressed : ButtonState::Hover;
else
button_state[i] = ButtonState::Hover;
} else
button_state[i] = ButtonState::Up;
buttonState[i] = ButtonState::Up;
}
}
}

Expand All @@ -229,8 +232,8 @@ void IngameWindow::Draw_()
// This needs a change in GetDrawPos to add this offset and also change all control-add-calls but would be much
// cleaner (no more hard coded offsets and we could restyle the ingame windows easily)
//
Rect drawRect = GetDrawRect();
Rect fullWndRect(drawRect.getOrigin() - borderSize, drawRect.getSize() + borderSize * 2u);
const Rect drawRect = GetDrawRect();
const Rect fullWndRect(drawRect.getOrigin() - borderSize, drawRect.getSize() + borderSize * 2u);
// Top
DrawRectangle(Rect(fullWndRect.getOrigin(), fullWndRect.getSize().x, borderSize.y), COLOR_BLACK);
// Left
Expand All @@ -242,48 +245,43 @@ void IngameWindow::Draw_()
DrawRectangle(Rect(fullWndRect.left, fullWndRect.bottom - borderSize.y, fullWndRect.getSize().x, borderSize.y),
COLOR_BLACK);

// Linkes oberes Teil
// Upper parts
glArchivItem_Bitmap* leftUpperImg = LOADER.GetImageN("resource", 36);
leftUpperImg->DrawFull(GetPos());
// Rechtes oberes Teil
glArchivItem_Bitmap* rightUpperImg = LOADER.GetImageN("resource", 37);
rightUpperImg->DrawFull(GetPos() + DrawPoint(GetSize().x - rightUpperImg->getWidth(), 0));

// Die beiden Buttons oben
static constexpr std::array<helpers::EnumArray<uint16_t, ButtonState>, 2> ids = {{{47, 55, 50}, {48, 56, 52}}};

// Titelleiste
if(isUserClosable_)
LOADER.GetImageN("resource", ids[0][button_state[0]])->DrawFull(GetPos());
// The 2 buttons
constexpr std::array<helpers::EnumArray<uint16_t, ButtonState>, 2> ids = {{{47, 55, 50}, {48, 56, 52}}};
if(closeBehavior_ != CloseBehavior::Custom)
LOADER.GetImageN("resource", ids[0][buttonState[0]])->DrawFull(GetPos());
if(!IsModal())
LOADER.GetImageN("resource", ids[1][button_state[1]])->DrawFull(GetPos() + DrawPoint(GetSize().x - 16, 0));

// Breite berechnen
unsigned title_width = GetSize().x - leftUpperImg->getWidth() - rightUpperImg->getWidth();
LOADER.GetImageN("resource", ids[1][buttonState[1]])->DrawFull(GetPos() + DrawPoint(GetSize().x - 16, 0));

unsigned short title_index;
// The title bar
unsigned titleIndex;
if(IsActive())
title_index = isMoving ? 44 : 43;
titleIndex = isMoving ? 44 : 43;
else
title_index = 42;
titleIndex = 42;

glArchivItem_Bitmap& titleImg = *LOADER.GetImageN("resource", title_index);
glArchivItem_Bitmap& titleImg = *LOADER.GetImageN("resource", titleIndex);
DrawPoint titleImgPos = GetPos() + DrawPoint(leftUpperImg->getWidth(), 0);
// Wieviel mal nebeneinanderzeichnen?
unsigned short title_count = title_width / titleImg.getWidth();
for(unsigned short i = 0; i < title_count; ++i)
const unsigned titleWidth = GetSize().x - leftUpperImg->getWidth() - rightUpperImg->getWidth();
// How often should the image be drawn to get the full width
unsigned tileCount = titleWidth / titleImg.getWidth();
for(unsigned i = 0; i < tileCount; ++i)
{
titleImg.DrawFull(titleImgPos);
titleImgPos.x += titleImg.getWidth();
}

// Rest zeichnen
unsigned short rest = title_width % titleImg.getWidth();

if(rest)
titleImg.DrawPart(Rect(titleImgPos, rest, titleImg.getHeight()));
// The remaining part (if any)
unsigned remainingTileSize = titleWidth % titleImg.getWidth();
if(remainingTileSize)
titleImg.DrawPart(Rect(titleImgPos, remainingTileSize, titleImg.getHeight()));

// Text auf die Leiste
// Text on the title bar
NormalFont->Draw(GetPos() + DrawPoint(GetSize().x, titleImg.getHeight()) / 2, title_,
FontStyle::CENTER | FontStyle::VCENTER, COLOR_YELLOW);

Expand All @@ -293,44 +291,42 @@ void IngameWindow::Draw_()
// Side bars
if(!isMinimized_)
{
unsigned side_height = GetSize().y - leftUpperImg->getHeight() - bottomBorderSideImg->getHeight();
unsigned sideHeight = GetSize().y - leftUpperImg->getHeight() - bottomBorderSideImg->getHeight();

glArchivItem_Bitmap* leftSideImg = LOADER.GetImageN("resource", 38);
glArchivItem_Bitmap* rightSideImg = LOADER.GetImageN("resource", 39);
title_count = side_height / leftSideImg->getHeight();
tileCount = sideHeight / leftSideImg->getHeight();
DrawPoint leftImgPos = GetPos() + DrawPoint(0, leftUpperImg->getHeight());
DrawPoint rightImgPos = leftImgPos + DrawPoint(GetSize().x - leftSideImg->getWidth(), 0);
for(unsigned short i = 0; i < title_count; ++i)
for(unsigned i = 0; i < tileCount; ++i)
{
leftSideImg->DrawFull(leftImgPos);
rightSideImg->DrawFull(rightImgPos);
rightImgPos.y = leftImgPos.y += leftSideImg->getHeight();
}

// Rest zeichnen
rest = side_height % leftSideImg->getHeight();

if(rest)
// And the partial part
remainingTileSize = sideHeight % leftSideImg->getHeight();
if(remainingTileSize)
{
leftSideImg->DrawPart(Rect(leftImgPos, leftSideImg->getWidth(), rest));
rightSideImg->DrawPart(Rect(rightImgPos, rightSideImg->getWidth(), rest));
leftSideImg->DrawPart(Rect(leftImgPos, leftSideImg->getWidth(), remainingTileSize));
rightSideImg->DrawPart(Rect(rightImgPos, rightSideImg->getWidth(), remainingTileSize));
}
}

// Untere Leiste
unsigned side_width = GetSize().x - bottomBorderSideImg->getWidth() * 2;
title_count = side_width / bottomBarImg->getWidth();
// Lower bar
const unsigned bottomBarWidth = GetSize().x - bottomBorderSideImg->getWidth() * 2;
tileCount = bottomBarWidth / bottomBarImg->getWidth();
DrawPoint bottomImgPos = GetPos() + DrawPoint(bottomBorderSideImg->getWidth(), GetRightBottomBoundary().y);
for(unsigned short i = 0; i < title_count; ++i)
for(unsigned i = 0; i < tileCount; ++i)
{
bottomBarImg->DrawFull(bottomImgPos);
bottomImgPos.x += bottomBarImg->getWidth();
}

rest = side_width % bottomBarImg->getWidth();

if(rest)
bottomBarImg->DrawPart(Rect(bottomImgPos, rest, bottomBarImg->getHeight()));
remainingTileSize = bottomBarWidth % bottomBarImg->getWidth();
if(remainingTileSize)
bottomBarImg->DrawPart(Rect(bottomImgPos, remainingTileSize, bottomBarImg->getHeight()));

// Client area
if(!isMinimized_)
Expand All @@ -341,40 +337,34 @@ void IngameWindow::Draw_()
Window::Draw_();
}

// Links und rechts unten die 2 kleinen Knäufe
// The 2 rects on the bottom left and right
bottomBorderSideImg->DrawFull(GetPos() + DrawPoint(0, GetSize().y - bottomBorderSideImg->getHeight()));
bottomBorderSideImg->DrawFull(
GetPos()
+ DrawPoint(GetSize().x - bottomBorderSideImg->getWidth(), GetSize().y - bottomBorderSideImg->getHeight()));
bottomBorderSideImg->DrawFull(GetPos() + GetSize() - bottomBorderSideImg->GetSize());
}

/// Verschiebt Fenster in die Bildschirmmitte
void IngameWindow::MoveToCenter()
{
SetPos(DrawPoint(VIDEODRIVER.GetRenderSize() - GetSize()) / 2);
}

/// Verschiebt Fenster neben die Maus
void IngameWindow::MoveNextToMouse()
{
// Center vertically and move slightly right
DrawPoint newPos = VIDEODRIVER.GetMousePos() - DrawPoint(-20, GetSize().y / 2);
SetPos(newPos);
}

/// Weiterleitung von Nachrichten erlaubt oder nicht?
bool IngameWindow::IsMessageRelayAllowed() const
{
// Wenn es minimiert wurde, sollen keine Nachrichten weitergeleitet werden
return !isMinimized_;
}

Rect IngameWindow::GetLeftButtonRect() const
Rect IngameWindow::GetCloseButtonBounds() const
{
return Rect(GetPos(), 16, 16);
}

Rect IngameWindow::GetRightButtonRect() const
Rect IngameWindow::GetMinimizeButtonBounds() const
{
return Rect(GetPos().x + GetSize().x - 16, GetPos().y, 16, 16);
}
Expand Down
30 changes: 20 additions & 10 deletions libs/s25main/ingameWindows/IngameWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ class MouseCoords;
template<typename T>
struct Point;

enum CloseBehavior
{
/// Closeable via right-click, button, keyboard (ESC, ALT+W)
Regular,
/// Close behavior is managed by window, e.g. explicit button
Custom,
/// Same as Regular, but doesn't (auto-)close on right-click
NoRightClick,
};

class IngameWindow : public Window
{
public:
Expand All @@ -27,8 +37,8 @@ class IngameWindow : public Window
static const Extent borderSize;

IngameWindow(unsigned id, const DrawPoint& pos, const Extent& size, std::string title,
glArchivItem_Bitmap* background, bool modal = false, bool isUserClosable = true,
Window* parent = nullptr);
glArchivItem_Bitmap* background, bool modal = false,
CloseBehavior closeBehavior = CloseBehavior::Regular, Window* parent = nullptr);

/// setzt den Hintergrund.
void SetBackground(glArchivItem_Bitmap* background) { this->background = background; }
Expand Down Expand Up @@ -61,11 +71,9 @@ class IngameWindow : public Window
/// ist das Fenster minimiert?
bool IsMinimized() const { return isMinimized_; }

/// Can the user close the window (e.g. right-click, ESC)
/// If this is false the close button at the title bar will be hidden
bool isUserClosable() const { return isUserClosable_; }
CloseBehavior getCloseBehavior() const { return closeBehavior_; }

/// Modal windows cannot be minimized and stay on top of non-modal ones
/// Modal windows cannot be minimized, are always active and stay on top of non-modal ones
bool IsModal() const { return isModal_; }

void MouseLeftDown(const MouseCoords& mc);
Expand Down Expand Up @@ -93,20 +101,22 @@ class IngameWindow : public Window
DrawPoint lastMousePos;
bool last_down;
bool last_down2;
std::array<ButtonState, 2> button_state;
std::array<ButtonState, 2> buttonState;

/// Offset from left and top to actual content
Extent contentOffset;
/// Offset from content to right and bottom boundary
Extent contentOffsetEnd;

Rect GetLeftButtonRect() const;
Rect GetRightButtonRect() const;
/// Get bounds of close button (left)
Rect GetCloseButtonBounds() const;
/// Get bounds of minimize button (right)
Rect GetMinimizeButtonBounds() const;

private:
bool isModal_;
bool closeme;
bool isMinimized_;
bool isMoving;
bool isUserClosable_;
CloseBehavior closeBehavior_;
};
Loading

0 comments on commit 397f2b2

Please sign in to comment.