[Scummvm-git-logs] scummvm master -> 34ecd753ad7939fdcab8e9227e245396e2c845ec

sev- noreply at scummvm.org
Wed Mar 27 14:34:38 UTC 2024


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
34ecd753ad GRAPHICS: MACGUI: Implement submenu scrolling


Commit: 34ecd753ad7939fdcab8e9227e245396e2c845ec
    https://github.com/scummvm/scummvm/commit/34ecd753ad7939fdcab8e9227e245396e2c845ec
Author: Krish (ganatrakrish2882005 at gmail.com)
Date: 2024-03-27T15:34:34+01:00

Commit Message:
GRAPHICS: MACGUI: Implement submenu scrolling

Changed paths:
    graphics/macgui/macmenu.cpp
    graphics/macgui/macmenu.h
    graphics/macgui/macpopupmenu.cpp


diff --git a/graphics/macgui/macmenu.cpp b/graphics/macgui/macmenu.cpp
index d51b723b60e..471b96022d3 100644
--- a/graphics/macgui/macmenu.cpp
+++ b/graphics/macgui/macmenu.cpp
@@ -25,6 +25,7 @@
 #include "common/macresman.h"
 #include "common/formats/winexe_pe.h"
 #include "common/unicode-bidi.h"
+#include "common/timer.h"
 
 #include "graphics/primitives.h"
 #include "graphics/font.h"
@@ -34,6 +35,8 @@
 #include "graphics/macgui/macwindow.h"
 #include "graphics/macgui/macmenu.h"
 
+#define SCROLL_DELAY 100000
+
 namespace Graphics {
 
 enum {
@@ -121,6 +124,11 @@ MacMenu::MacMenu(int id, const Common::Rect &bounds, MacWindowManager *wm)
 	_unicodeccallback = NULL;
 	_cdata = NULL;
 
+	_scrollTimerActive = false;
+	_scrollDirection = 0;
+
+	_isModal = false;
+
 	_tempSurface.create(_screen.w, _font->getFontHeight(), PixelFormat::createFormatCLUT8());
 }
 
@@ -937,8 +945,8 @@ void MacMenu::calcSubMenuBounds(MacMenuSubMenu *submenu, int x, int y) {
 	int x1 = x;
 	int y1 = y;
 	int x2 = x1 + maxWidth + _menuLeftDropdownPadding + _menuRightDropdownPadding - 4;
-
 	int y2 = y1 + submenu->items.size() * _menuDropdownItemHeight + 2;
+	y2 = MIN(y2, y1 + ((_screen.h - y1) / _menuDropdownItemHeight) * _menuDropdownItemHeight + 2);
 
 	submenu->bbox.left = x1;
 	submenu->bbox.top = y1;
@@ -1089,7 +1097,27 @@ void MacMenu::renderSubmenu(MacMenuSubMenu *menu, bool recursive) {
 	int x = _align == kTextAlignRight ? -_menuRightDropdownPadding: _menuLeftDropdownPadding;
 	x += r->left;
 
-	for (uint i = 0; i < menu->items.size(); i++) {
+	int maxVis = menu->bbox.height() / _menuDropdownItemHeight;
+	int numVis = menu->items.size() - menu->visStart - menu->visEnd + ABS(menu->scroll);
+	numVis = MIN(numVis, maxVis);
+
+	int ovTop = menu->visStart + menu->scroll; // Number of items overflowing from top
+	int ovBot = menu->items.size() - ovTop - numVis; // Number of items overflowing from bottom
+
+	for (uint i = menu->visStart + menu->scroll; i < menu->items.size(); i++) {
+		if ((ovTop && i == menu->visStart + menu->scroll) ||
+			(ovBot && i == numVis - 1 + menu->scroll + menu->visStart)) {
+			int direction = (i == menu->visStart + menu->scroll) ? 1 : -1;
+
+			int arrowX = _align == kTextAlignRight ? menu->bbox.right - _menuRightDropdownPadding : menu->bbox.left + _menuLeftDropdownPadding;
+			int arrowY = direction == 1 ? menu->bbox.top + _menuDropdownItemHeight / 2 : menu->bbox.bottom - _menuDropdownItemHeight / 2;
+
+			drawScrollArrow(arrowX, arrowY, direction);
+
+			y += _menuDropdownItemHeight;
+			continue;
+		}
+
 		Common::String text(menu->items[i]->text);
 		Common::String acceleratorText(getAcceleratorString(menu->items[i], ""));
 
@@ -1257,8 +1285,32 @@ bool MacMenu::checkIntersects(Common::Rect &rect) {
 	return false;
 }
 
+static void scrollCallback(void *data) {
+	MacMenu *menu = (MacMenu *)data;
+	MacMenuSubMenu *subMenu = menu->_menustack.back();
+
+	int maxVis = subMenu->bbox.height() / menu->getDropdownItemHeight();
+	int numVis = subMenu->items.size() - subMenu->visStart - subMenu->visEnd + ABS(subMenu->scroll);
+	numVis = MIN(numVis, maxVis);
+
+	int ovTop = subMenu->visStart + subMenu->scroll; // Number of items overflowing from top
+	int ovBot = subMenu->items.size() - ovTop - numVis; // Number of items overflowing from bottom
+
+	if (menu->getScrollDirection() == -1) {
+		if (ovTop) {
+			subMenu->scroll--;
+			menu->renderSubmenu(subMenu);
+		}
+	} else {
+		if (ovBot) {
+			subMenu->scroll++;
+			menu->renderSubmenu(subMenu);
+		}
+	}
+}
+
 bool MacMenu::mouseClick(int x, int y) {
-	if (_bbox.contains(x, y)) {
+	if (!_isModal &&_bbox.contains(x, y)) {
 		for (uint i = 0; i < _items.size(); i++) {
 			if (_items[i]->bbox.contains(x, y)) {
 				if ((uint)_activeItem == i)
@@ -1298,20 +1350,62 @@ bool MacMenu::mouseClick(int x, int y) {
 	if (_menustack.size() > 0 && _menustack.back()->bbox.contains(x, y)) {
 		MacMenuSubMenu *menu = _menustack.back();
 		int numSubItem = menu->ytoItem(y, _menuDropdownItemHeight);
+		int selectedOption = numSubItem;
+		numSubItem += menu->visStart + menu->scroll;
+		numSubItem = MIN((uint)numSubItem, menu->items.size() - 1);
 
 		if (numSubItem != _activeSubItem) {
 			if (_wm->_mode & kWMModalMenuMode) {
 				if (_activeSubItem == -1 || menu->items[_activeSubItem]->submenu != nullptr)
 					g_system->copyRectToScreen(_wm->_screenCopy->getPixels(), _wm->_screenCopy->pitch, 0, 0, _wm->_screenCopy->w, _wm->_screenCopy->h);
 			}
-			_activeSubItem = numSubItem;
-			menu->highlight = _activeSubItem;
+
+			int maxVis = menu->bbox.height() / _menuDropdownItemHeight;
+			int numItemsVisible = menu->items.size() - menu->visStart - menu->visEnd + ABS(menu->scroll);
+			numItemsVisible = MIN(numItemsVisible, maxVis);
+
+			int ovTop = menu->visStart + menu->scroll;
+			int ovBot = menu->items.size() - ovTop - numItemsVisible;
+
+			// If the user clicks on the "Scroll Up Arrow" or the "Scroll Down Arrow" then ignore the selection
+			if (!(ovTop && selectedOption == 0) && !(ovBot && numItemsVisible == maxVis && menu->ytoItem(y, _menuDropdownItemHeight) == numItemsVisible - 1)) {
+				_activeSubItem = numSubItem;
+				menu->highlight = _activeSubItem;
+			}
+
+			if (selectedOption == 0) {
+				if (ovTop) {
+					if (!_scrollTimerActive) {
+						_scrollDirection = -1;
+						_scrollTimerActive = true;
+						g_system->getTimerManager()->installTimerProc(&scrollCallback, SCROLL_DELAY, this, "Scroll Up Handler");
+					}
+				}
+			} else if (selectedOption == numItemsVisible - 1) {
+				if (ovBot && numItemsVisible == maxVis) {
+					if (!_scrollTimerActive) {
+						_scrollDirection = 1;
+						_scrollTimerActive = true;
+						g_system->getTimerManager()->installTimerProc(&scrollCallback, SCROLL_DELAY, this, "Scroll Down Handler");
+					}
+				}
+			} else {
+				if (_scrollTimerActive) {
+					_scrollTimerActive = false;
+					g_system->getTimerManager()->removeTimerProc(&scrollCallback);
+				}
+			}
 
 			_contentIsDirty = true;
 			_wm->setFullRefresh(true);
 		}
 
 		return true;
+	} else {
+		if (_scrollTimerActive) {
+			_scrollTimerActive = false;
+			g_system->getTimerManager()->removeTimerProc(&scrollCallback);
+		}
 	}
 
 	if (_activeSubItem != -1 && _menustack.back()->items[_activeSubItem]->submenu != nullptr) {
@@ -1381,6 +1475,13 @@ bool MacMenu::contains(int x, int y) {
 	return false;
 }
 
+void MacMenu::drawScrollArrow(int arrowX, int arrowY, int direction) {
+	int arrowHeight = getMenuFont()->getFontHeight() / 2;
+
+	for (int j = 0; j <= arrowHeight / 2; j++)
+		_screen.hLine(arrowX - j, arrowY + j * direction, arrowX + j, _wm->_colorBlack);
+}
+
 bool MacMenu::mouseMove(int x, int y) {
 	if (_active) {
 		if (mouseClick(x, y))
@@ -1413,6 +1514,12 @@ bool MacMenu::checkCallback(bool unicode) {
 
 void MacMenu::closeMenu() {
 	setActive(false);
+
+	if (_scrollTimerActive) {
+		_scrollTimerActive = false;
+		g_system->getTimerManager()->removeTimerProc(&scrollCallback);
+	}
+
 	if (_wm->_mode & kWMModeAutohideMenu)
 		_isVisible = false;
 
diff --git a/graphics/macgui/macmenu.h b/graphics/macgui/macmenu.h
index be27d80b604..5f3cd0aa099 100644
--- a/graphics/macgui/macmenu.h
+++ b/graphics/macgui/macmenu.h
@@ -43,8 +43,11 @@ struct MacMenuSubMenu {
 	ItemArray items;
 	Common::Rect bbox;
 	int highlight;
+	int visStart; // Visible start
+	int visEnd; // Visible end
+	int scroll;
 
-	MacMenuSubMenu() : highlight(-1) {}
+	MacMenuSubMenu() : highlight(-1), visStart(0), visEnd(0), scroll(0) {}
 
 	~MacMenuSubMenu();
 
@@ -168,6 +171,14 @@ public:
 	int getLastSelectedMenuItem() { return _lastActiveItem; };
 	int getLastSelectedSubmenuItem() { return _lastActiveSubItem; };
 
+	void renderSubmenu(MacMenuSubMenu *menu, bool recursive = true);
+
+	int getScrollDirection() { return _scrollDirection; }
+
+	int getDropdownItemHeight() { return _menuDropdownItemHeight; }
+
+	Common::Array<MacMenuSubMenu *> _menustack;
+
 protected:
 	Common::Rect _bbox;
 	ManagedSurface _screen;
@@ -175,12 +186,12 @@ protected:
 	bool _isVisible;
 	bool _dimensionsDirty;
 	int _menuDropdownItemHeight;
-	Common::Array<MacMenuSubMenu *> _menustack;
 
 	int _activeItem;
 	int _activeSubItem;
 
-	void renderSubmenu(MacMenuSubMenu *menu, bool recursive = true);
+	bool _isModal;
+
 	void calcSubMenuBounds(MacMenuSubMenu *menu, int x, int y);
 
 private:
@@ -207,6 +218,8 @@ private:
 	void drawSubMenuArrow(ManagedSurface *dst, int x, int y, int color);
 	bool contains(int x, int y);
 
+	void drawScrollArrow(int arrowX, int arrowY, int direction);
+
 	MacMenuItem *findMenuItem(const Common::String &menuId, const Common::String &itemId);
 	MacMenuItem *findMenuItem(int menuId, int itemId);
 
@@ -217,6 +230,9 @@ private:
 	int _lastActiveItem;
 	int _lastActiveSubItem;
 
+	bool _scrollTimerActive;
+	int _scrollDirection;
+
 	void (*_ccallback)(int action, Common::String &text, void *data);
 	void (*_unicodeccallback)(int action, Common::U32String &text, void *data);
 	void *_cdata;
diff --git a/graphics/macgui/macpopupmenu.cpp b/graphics/macgui/macpopupmenu.cpp
index bd042323963..ba3461c301f 100644
--- a/graphics/macgui/macpopupmenu.cpp
+++ b/graphics/macgui/macpopupmenu.cpp
@@ -90,6 +90,8 @@ void MacPopUp::closeMenu() {
 		_prevCheckedItem = activeSubItem;
 	}
 
+	_isModal = false;
+
 	// Close now
 	MacMenu::closeMenu();
 }
@@ -105,10 +107,37 @@ uint32 MacPopUp::drawAndSelectMenu(int x, int y, int item) {
 
 	_contentIsDirty = true; // Set true to force refresh menu open changes
 
+	_isModal = true;
+
 	// Push our submenu to stack
 	_menustack.clear();
 	_menustack.push_back(_items[0]->submenu);
 
+	_items[0]->submenu->visStart = 0;
+	_items[0]->submenu->visEnd = 0;
+	_items[0]->submenu->scroll = 0;
+	_offsetY = 0;
+
+	if (_isSmart) {
+		int activeSubItem = getLastSelectedSubmenuItem();
+
+		if (activeSubItem != -1)
+			_offsetY = -activeSubItem * _menuDropdownItemHeight;
+		else if (_prevCheckedItem != -1)
+			_offsetY = -_prevCheckedItem * _menuDropdownItemHeight;
+
+		while (_offsetY + _mouseY < 0) {
+			_offsetY += _menuDropdownItemHeight;
+
+			_items[0]->submenu->visStart++;
+		}
+
+		int itemsLeft = _items[0]->submenu->items.size() - _items[0]->submenu->visStart;
+		int spaceLeft = _screen.h - MIN(_mouseY + _offsetY, _mouseY);
+		_items[0]->submenu->visEnd = MAX(0, itemsLeft - spaceLeft / _menuDropdownItemHeight);
+	}
+
+
 	// Highlight previous item if smart menu
 	if (_isSmart && getLastSelectedSubmenuItem() != -1) {
 		_activeItem = 0;




More information about the Scummvm-git-logs mailing list