summaryrefslogtreecommitdiff
path: root/freefilesync/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'freefilesync/debian/patches')
-rw-r--r--freefilesync/debian/patches/ffs_traditional_view.patch501
-rw-r--r--freefilesync/debian/patches/series2
2 files changed, 461 insertions, 42 deletions
diff --git a/freefilesync/debian/patches/ffs_traditional_view.patch b/freefilesync/debian/patches/ffs_traditional_view.patch
index 5e6e7ff..c74bef2 100644
--- a/freefilesync/debian/patches/ffs_traditional_view.patch
+++ b/freefilesync/debian/patches/ffs_traditional_view.patch
@@ -1,10 +1,82 @@
-Version: 13.0
-Date: 2023-09-13
+Version: 13.5
+Date: 2024-04-03
Author: bgstack15
-Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVersion" About dialog
---- a/FreeFileSync/Source/ui/file_grid.cpp
-+++ b/FreeFileSync/Source/ui/file_grid.cpp
-@@ -487,8 +487,10 @@ private:
+Message:
+ Restore a traditional view to FreeFileSync by just using the entire patched
+ 13.4 file_grip.cpp. The changes to file_grid.cpp were too extensive for my
+ intended level of effort. This means that this patch undoes the bullet point
+ "Wrap file grid folder paths instead of truncate" in the Latest Changes.
+--- a/FreeFileSync/Source/ui/file_grid.cpp 2024-04-02 09:18:16.161133752 -0400
++++ b/FreeFileSync/Source/ui/file_grid.cpp 2024-04-03 16:56:12.513543859 -0400
+@@ -308,8 +308,7 @@
+ NavigationMarker navMarker;
+ std::unique_ptr<GridEventManager> evtMgr;
+ GridViewType gridViewType = GridViewType::action;
+- std::unordered_map<std::wstring, wxSize, StringHash, StringEqual> compExtentsBuf_; //buffer expensive wxDC::GetTextExtent() calls!
+- //StringHash, StringEqual => heterogenous lookup by std::wstring_view
++ std::unordered_map<std::wstring, wxSize> compExtentsBuf_; //buffer expensive wxDC::GetTextExtent() calls!
+ };
+
+ //########################################################################################################
+@@ -352,7 +351,7 @@
+
+ const FileSystemObject* getFsObject(size_t row) const { return getDataView().getFsObject(row); }
+
+- const wxSize& getTextExtentBuffered(wxDC& dc, const std::wstring_view& text)
++ const wxSize& getTextExtentBuffered(wxDC& dc, const std::wstring& text)
+ {
+ auto& compExtentsBuf = sharedComp_.ref().compExtentsBuf_;
+ //- only used for parent path names and file names on view => should not grow "too big"
+@@ -360,47 +359,10 @@
+
+ auto it = compExtentsBuf.find(text);
+ if (it == compExtentsBuf.end())
+- it = compExtentsBuf.emplace(text, dc.GetTextExtent(copyStringTo<wxString>(text))).first;
++ it = compExtentsBuf.emplace(text, dc.GetTextExtent(text)).first;
+ return it->second;
+ }
+
+- //- trim while leaving path components intact
+- //- *always* returns at least one component, even if > maxWidth
+- size_t getPathTrimmedSize(wxDC& dc, const std::wstring_view& itemPath, int maxWidth)
+- {
+- if (itemPath.size() <= 1)
+- return itemPath.size();
+-
+- std::vector<std::wstring_view> subComp;
+-
+- //split path by components, but skip slash at beginning or end
+- for (auto it = itemPath.begin() + 1; it != itemPath.end() - 1; ++it)
+- if (*it == L'/' ||
+- *it == L'\\')
+- subComp.push_back(makeStringView(itemPath.begin(), it));
+-
+- subComp.push_back(itemPath);
+-
+- if (maxWidth <= 0)
+- return subComp[0].size();
+-
+- size_t low = 0;
+- size_t high = subComp.size();
+-
+- for (;;)
+- {
+- if (high - low == 1)
+- return subComp[low].size();
+-
+- const size_t middle = (low + high) / 2; //=> never 0 when "high - low > 1"
+-
+- if (getTextExtentBuffered(dc, subComp[middle]).GetWidth() <= maxWidth)
+- low = middle;
+- else
+- high = middle;
+- }
+- }
+-
+ private:
+ size_t getRowCount() const override { return getDataView().rowsOnView(); }
+
+@@ -525,8 +487,10 @@
case ItemPathFormat::name:
return utfTo<std::wstring>(fsObj->getItemName<side>());
case ItemPathFormat::relative:
@@ -15,7 +87,7 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
return AFS::getDisplayPath(fsObj->getAbstractPath<side>());
}
-@@ -548,6 +550,11 @@ private:
+@@ -586,11 +550,14 @@
else
GridData::renderRowBackgound(dc, rect, row, true /*enabled*/, true /*selected*/, rowHover);
@@ -26,15 +98,90 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
+
//----------------------------------------------------------------------------------
const wxRect rectLine(rect.x, rect.y + rect.height - dipToWxsize(1), rect.width, dipToWxsize(1));
- clearArea(dc, rectLine, row == pdi.groupLastRow - 1 /*last group item*/ ?
-@@ -658,6 +665,26 @@ private:
+- clearArea(dc, rectLine, row == pdi.groupLastRow - 1 || //last group item
+- (pdi.fsObj == pdi.folderGroupObj && //folder item => distinctive separation color against subsequent file items
+- itemPathFormat_ != ItemPathFormat::name) ?
++ clearArea(dc, rectLine, row == pdi.groupLastRow - 1 /*last group item*/ ?
+ getColorGridLine() : getDefaultBackgroundColorAlternating(pdi.groupIdx % 2 != 0));
+ }
+
+@@ -612,18 +579,18 @@
+ if (itemNamesWidth < 0)
+ {
+ itemNamesWidth = 0;
+- //const int ellipsisWidth = getTextExtentBuffered(dc, ELLIPSIS).x;
++ const int ellipsisWidth = getTextExtentBuffered(dc, ELLIPSIS).x;
+
+ std::vector<int> itemWidths;
+ for (size_t row2 = pdi.groupFirstRow; row2 < pdi.groupLastRow; ++row2)
+ if (const FileSystemObject* fsObj = getDataView().getFsObject(row2))
+ if (itemPathFormat_ == ItemPathFormat::name || fsObj != pdi.folderGroupObj)
+-#if 0 //render same layout even when items don't exist
++ {
+ if (fsObj->isEmpty<side>())
+ itemNamesWidth = ellipsisWidth;
+ else
+-#endif
+ itemWidths.push_back(getTextExtentBuffered(dc, utfTo<std::wstring>(fsObj->getItemName<side>())).x);
++ }
+
+ if (!itemWidths.empty())
+ {
+@@ -641,15 +608,17 @@
+ }
+
+
+- struct GroupRowLayout
++ struct GroupRenderLayout
+ {
+- std::wstring groupParentPart; //... if distributed over multiple rows, otherswise full group parent folder
+- std::wstring groupName; //only filled for first row of a group
+ std::wstring itemName;
++ std::wstring groupName;
++ std::wstring groupParentFolder;
++ size_t groupFirstRow;
++ bool stackedGroupRender;
+ int groupParentWidth;
+ int groupNameWidth;
+ };
+- GroupRowLayout getGroupRowLayout(wxDC& dc, size_t row, const FileView::PathDrawInfo& pdi, int maxWidth)
++ GroupRenderLayout getGroupRenderLayout(wxDC& dc, size_t row, const FileView::PathDrawInfo& pdi, int maxWidth)
+ {
+ assert(pdi.fsObj);
+
+@@ -657,15 +626,14 @@
+ const int iconSize = getIconManager().getIconWxsize();
+
+ //--------------------------------------------------------------------
+- const int ellipsisWidth = getTextExtentBuffered(dc, ELLIPSIS).x;
+- const int arrowRightDownWidth = getTextExtentBuffered(dc, rightArrowDown_).x;
++ const int ellipsisWidth = getTextExtentBuffered(dc, ELLIPSIS).x;
+ const int groupItemNamesWidth = getGroupItemNamesWidth(dc, pdi);
+ //--------------------------------------------------------------------
+
+ //exception for readability: top row is always group start!
+ const size_t groupFirstRow = std::max<size_t>(pdi.groupFirstRow, refGrid().getRowAtWinPos(0));
+
+- const size_t groupLineCount = pdi.groupLastRow - groupFirstRow;
++ const bool multiItemGroup = pdi.groupLastRow - groupFirstRow > 1;
+
+ std::wstring itemName;
+ if (itemPathFormat_ == ItemPathFormat::name || //hack: show folder name in item colum since groupName/groupParentFolder are unused!
+@@ -697,140 +665,166 @@
else //=> BaseFolderPair
groupParentFolder = AFS::getDisplayPath(pdi.fsObj->base().getAbstractPath<side>());
break;
-+
+- }
+
+- if (!groupParentFolder.empty())
+- {
+- const wchar_t pathSep = [&]
+- {
+- for (auto it = groupParentFolder.end(); it != groupParentFolder.begin();) //reverse iteration: 1. check 2. decrement 3. evaluate
+ case ItemPathFormat::traditional:
+ if (auto groupFolder = dynamic_cast<const FolderPair*>(pdi.folderGroupObj))
-+ {
+ {
+- --it; //
+ groupName = utfTo<std::wstring>(groupFolder->template getItemName<side>());
+ groupParentFolder = AFS::getDisplayPath(groupFolder->parent().template getAbstractPath<side>()) + \
+ FILE_NAME_SEPARATOR + utfTo<std::wstring>(groupFolder->template getItemName<side>());
@@ -42,19 +189,53 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
+ else //=> BaseFolderPair
+ groupParentFolder = AFS::getDisplayPath(pdi.fsObj->base().getAbstractPath<side>());
+ break;
-+
+
+- if (*it == L'/' ||
+- *it == L'\\')
+- return *it;
+ case ItemPathFormat::tradrel:
+ if (pdi.folderGroupObj)
+ {
+ groupName = utfTo<std::wstring>(pdi.folderGroupObj->template getItemName <side>());
+ groupParentFolder = utfTo<std::wstring>(pdi.folderGroupObj->template getRelativePath<side>());
-+ }
+ }
+- return static_cast<wchar_t>(FILE_NAME_SEPARATOR);
+- }();
+- if (!endsWith(groupParentFolder, pathSep)) //visual hint that this is a parent folder only
+- groupParentFolder += pathSep; //
+ break;
+
}
- //path components should follow the app layout direction and are NOT a single piece of text!
-@@ -683,11 +710,38 @@ private:
++ //path components should follow the app layout direction and are NOT a single piece of text!
++ //caveat: add Bidi support only during rendering and not in getValue() or AFS::getDisplayPath(): e.g. support "open file in Explorer"
++ assert(!contains(groupParentFolder, slashBidi_) && !contains(groupParentFolder, bslashBidi_));
++ replace(groupParentFolder, L'/', slashBidi_);
++ replace(groupParentFolder, L'\\', bslashBidi_);
++
+ /* group details: single row
+ ________________________ ___________________________________ _____________________________________________________
+ | (gap | group parent) | | (gap | icon | gap | group name) | | (2x gap | vline) | (gap | icon) | gap | item name |
+ ------------------------ ----------------------------------- -----------------------------------------------------
+
+ group details: stacked
+- __________________________________ ___________________________________ ___________________________________________________
+- | gap | group parent, part 1 | ⤵️ | <right-aligned> | (gap | icon | gap | group name) | | | (gap | icon) | gap | item name |
+- |-------------------------------------------------------------------------------------| | 2x gap | vline |--------------------------------|
+- | gap | group parent, part n | | | (gap | icon) | gap | item name |
+- --------------------------------------------------------------------------------------- ---------------------------------------------------
+-
+- -> group name on first row
+- -> parent name distributed over multiple rows, if needed */
+-
++ _____________________________________________________ _____________________________________________________
++ | <right-aligned> (gap | icon | gap | group name) | | | (gap | icon) | gap | item name | <- group name on first row
++ |---------------------------------------------------| | (2x gap | vline) |--------------------------------|
++ | (gap | group parent_/\ | wide gap) | | | (gap | icon) | gap | item name | <- group parent on second
++ ----------------------------------------------------- ----------------------------------------------------- */
++ bool stackedGroupRender = false;
+ int groupParentWidth = groupParentFolder.empty() ? 0 : (gapSize_ + getTextExtentBuffered(dc, groupParentFolder).x);
+
int groupNameWidth = groupName.empty() ? 0 : (gapSize_ + iconSize + gapSize_ + getTextExtentBuffered(dc, groupName).x);
const int groupNameMinWidth = groupName.empty() ? 0 : (gapSize_ + iconSize + gapSize_ + ellipsisWidth);
@@ -70,6 +251,9 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
int groupItemsWidth = groupSepWidth + (drawFileIcons ? gapSize_ + iconSize : 0) + gapSize_ + groupItemNamesWidth;
const int groupItemsMinWidth = groupSepWidth + (drawFileIcons ? gapSize_ + iconSize : 0) + gapSize_ + ellipsisWidth;
+- std::wstring groupParentPart;
+- if (row == groupFirstRow)
+- groupParentPart = groupParentFolder;
+ // start trad patch
+
+ // rearrange this one section
@@ -90,33 +274,199 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
+ // the insane logic of the new views
+ // but preserve the original tabbing, to make the patch easier.
+ // but with the "add slashes" paragraph 1 moved to above this switch statement!
-+
- //not enough space? => collapse
+
+- //not enough space? => trim or render on multiple rows
++ //not enough space? => collapse
if (int excessWidth = groupParentWidth + groupNameWidth + groupItemsWidth - maxWidth;
excessWidth > 0)
-@@ -754,6 +808,11 @@ private:
+ {
+- const bool stackedGroupRender = !groupParentFolder.empty() && groupLineCount > 1; //group parent details on multiple rows
+-
+- //1. shrink group parent
+- if (!groupParentFolder.empty())
++ if (multiItemGroup && !groupParentFolder.empty() && !groupName.empty())
+ {
+- const int groupParentMinWidth = stackedGroupRender && !groupName.empty() ? 0 : gapSize_ + ellipsisWidth;
++ //1. render group components on two rows
++ stackedGroupRender = true;
+
+- groupParentWidth = std::max(groupParentWidth - excessWidth, groupParentMinWidth);
+- excessWidth = groupParentWidth + groupNameWidth + groupItemsWidth - maxWidth;
+- }
++ //add Unicode arrow to indicate that path was split
++ groupParentFolder += L'\u2934'; //Right Arrow Curving Up
+
+- if (excessWidth > 0)
+- {
+- //2. shrink item rendering
+- groupItemsWidth = std::max(groupItemsWidth - excessWidth, groupItemsMinWidth);
+- excessWidth = groupParentWidth + groupNameWidth + groupItemsWidth - maxWidth;
++ const int groupParentMinWidth = gapSize_ + ellipsisWidth + gapSizeWide_;
++ groupParentWidth = gapSize_ + getTextExtentBuffered(dc, groupParentFolder).x + gapSizeWide_;
+
+- if (excessWidth > 0)
+- //3. shrink group name
+- if (!groupName.empty())
+- groupNameWidth = std::max(groupNameWidth - excessWidth, groupNameMinWidth);
+- }
++ int groupStackWidth = std::max(groupParentWidth, groupNameWidth);
++ excessWidth = groupStackWidth + groupItemsWidth - maxWidth;
+
+- if (stackedGroupRender)
+- {
+- size_t comp1Len = getPathTrimmedSize(dc, groupParentFolder, groupParentWidth - gapSize_ - arrowRightDownWidth);
++ if (excessWidth > 0)
++ {
++ //2. shrink group stack (group parent only)
++ if (groupParentWidth > groupNameWidth)
++ {
++ groupStackWidth = groupParentWidth = std::max({groupParentWidth - excessWidth, groupNameWidth, groupParentMinWidth});
++ excessWidth = groupStackWidth + groupItemsWidth - maxWidth;
++ }
++ if (excessWidth > 0)
++ {
++ //3. shrink item rendering
++ groupItemsWidth = std::max(groupItemsWidth - excessWidth, groupItemsMinWidth);
++ excessWidth = groupStackWidth + groupItemsWidth - maxWidth;
+
+- if (!groupName.empty() &&
+- getTextExtentBuffered(dc, makeStringView(groupParentFolder.begin(), comp1Len)).x > groupParentWidth - gapSize_ - arrowRightDownWidth)
+- comp1Len = 0; //exception: never truncate parent component on first row, but move to second row instead
++ if (excessWidth > 0)
++ {
++ //4. shrink group stack
++ groupStackWidth = std::max({groupStackWidth - excessWidth, groupNameMinWidth, groupParentMinWidth});
+
+- if (row == groupFirstRow)
++ groupParentWidth = std::min(groupParentWidth, groupStackWidth);
++ groupNameWidth = std::min(groupNameWidth, groupStackWidth);
++ }
++ }
++ }
++ }
++ else //group details on single row
++ {
++ //1. shrink group parent
++ if (!groupParentFolder.empty())
+ {
+- groupParentPart = groupParentFolder.substr(0, comp1Len);
+-
+- if (comp1Len != 0 && comp1Len != groupParentFolder.size())
+- groupParentPart += rightArrowDown_;
++ const int groupParentMinWidth = gapSize_ + ellipsisWidth;
++ groupParentWidth = std::max(groupParentWidth - excessWidth, groupParentMinWidth);
++ excessWidth = groupParentWidth + groupNameWidth + groupItemsWidth - maxWidth;
+ }
+- else
++ if (excessWidth > 0)
+ {
+- size_t compPos = comp1Len;
+-
+- for (size_t i = groupFirstRow + 1; ; ++i)
+- {
+- const size_t compLen = getPathTrimmedSize(dc, makeStringView(groupParentFolder.begin() + compPos, groupParentFolder.end()),
+- groupParentWidth + groupNameWidth - gapSize_ - arrowRightDownWidth);
+- if (row == i)
+- {
+- groupParentPart = compPos + compLen == groupParentFolder.size() ||
+- row == pdi.groupLastRow - 1 ? //not enough rows to show all parent folder components?
+- groupParentFolder.substr(compPos) : //=> append to last row => will be truncated with ellipsis
+- groupParentFolder.substr(compPos, compLen) + rightArrowDown_;
+- break;
+- }
+- compPos += compLen;
++ //2. shrink item rendering
++ groupItemsWidth = std::max(groupItemsWidth - excessWidth, groupItemsMinWidth);
++ excessWidth = groupParentWidth + groupNameWidth + groupItemsWidth - maxWidth;
+
+- if (compPos == groupParentFolder.size())
+- break;
+- }
++ if (excessWidth > 0)
++ //3. shrink group name
++ if (!groupName.empty())
++ groupNameWidth = std::max(groupNameWidth - excessWidth, groupNameMinWidth);
+ }
}
}
+- //path components should follow the app layout direction and are NOT a single piece of text!
+- //caveat: - add Bidi support only during rendering and not in getValue() or AFS::getDisplayPath(): e.g. support "open file in Explorer"
+- // - add *after* getPathTrimmedSize(), otherwise LTR-mark can be confused for path component, e.g. "<LTR>/home" would be two components!
+- assert(!contains(groupParentPart, slashBidi_) && !contains(groupParentPart, bslashBidi_));
+- replace(groupParentPart, L'/', slashBidi_);
+- replace(groupParentPart, L'\\', bslashBidi_);
+ // end of original section, and back to the trad patch!
+ break;
+ }
+ // and end the addition for trad patch
-+
+
return
{
- itemName,
-@@ -894,6 +953,9 @@ private:
+- std::move(groupParentPart),
+- row == groupFirstRow ? std::move(groupName) : std::wstring{},
+- std::move(itemName),
+- row == groupFirstRow ? groupParentWidth : groupParentWidth + groupNameWidth,
+- row == groupFirstRow ? groupNameWidth : 0,
++ itemName,
++ groupName,
++ groupParentFolder,
++ groupFirstRow,
++ stackedGroupRender,
++ groupParentWidth,
++ groupNameWidth,
+ };
+ }
+
+-
+ void renderCell(wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool enabled, bool selected, HoverArea rowHover) override
+ {
+ //-----------------------------------------------
+@@ -947,43 +941,62 @@
+ };
+ //-------------------------------------------------------------------------
+
+- const auto& [groupParentPart,
++ const auto& [itemName,
+ groupName,
+- itemName,
++ groupParentFolder,
++ groupFirstRow,
++ stackedGroupRender,
+ groupParentWidth,
+- groupNameWidth] = getGroupRowLayout(dc, row, pdi, rectTmp.width);
++ groupNameWidth] = getGroupRenderLayout(dc, row, pdi, rectTmp.width);
+
+ wxRect rectGroup, rectGroupParent, rectGroupName;
rectGroup = rectGroupParent = rectGroupName = rectTmp;
+- rectGroup .width = groupParentWidth + groupNameWidth;
rectGroupParent.width = groupParentWidth;
+ // re-add back the width of groupname so that the directory name is clickable
+ if (itemPathFormat_ == ItemPathFormat::traditional || itemPathFormat_ == ItemPathFormat::tradrel)
+ rectGroupParent.width += groupNameWidth;
rectGroupName .width = groupNameWidth;
+- rectGroupName.x += groupParentWidth;
+
++ if (stackedGroupRender)
++ {
++ rectGroup.width = std::max(groupParentWidth, groupNameWidth);
++ rectGroupName.x += rectGroup.width - groupNameWidth; //right-align
++ }
++ else //group details on single row
++ {
++ rectGroup.width = groupParentWidth + groupNameWidth;
++ rectGroupName.x += groupParentWidth;
++ }
+ rectTmp.x += rectGroup.width;
+ rectTmp.width -= rectGroup.width;
- if (stackedGroupRender)
-@@ -917,6 +979,11 @@ private:
+ wxRect rectGroupItems = rectTmp;
+
+- if (itemName.empty()) //expand group name to include unused item area (e.g. bigger selection border)
++ if (itemName.empty()) //expand group name to include (empty) item area
+ {
+ rectGroupName.width += rectGroupItems.width;
rectGroupItems.width = 0;
}
@@ -128,7 +478,12 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
//-------------------------------------------------------------------------
{
//clear background below parent path => harmonize with renderRowBackgound()
-@@ -928,7 +995,8 @@ private:
+ wxDCTextColourChanger textColorGroup(dc);
+- if (rectGroup.width > 0 &&
++ if ((!groupParentFolder.empty() || !groupName.empty()) &&
+ (!enabled || !selected))
+ {
+ wxRect rectGroupBack = rectGroup;
rectGroupBack.width += 2 * gapSize_; //include gap before vline
if (row == pdi.groupLastRow - 1 /*last group item*/) //preserve the group separation line!
@@ -138,43 +493,95 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
clearArea(dc, rectGroupBack, getDefaultBackgroundColorAlternating(pdi.groupIdx % 2 == 0));
//clearArea() is surprisingly expensive => call just once!
-@@ -936,9 +1004,9 @@ private:
+@@ -991,18 +1004,22 @@
//accessibility: always set *both* foreground AND background colors!
}
-- if (!groupParentFolder.empty() &&
+- if (!groupParentPart.empty() &&
+- (!pdi.folderGroupObj || !pdi.folderGroupObj->isEmpty<side>())) //don't show for missing folders
+ if (itemPathFormat_ == ItemPathFormat::traditional || itemPathFormat_ == ItemPathFormat::tradrel || (!groupParentFolder.empty() &&
- (( stackedGroupRender && row == groupFirstRow + 1) ||
-- (!stackedGroupRender && row == groupFirstRow)) &&
++ (( stackedGroupRender && row == groupFirstRow + 1) ||
+ (!stackedGroupRender && row == groupFirstRow))) &&
- (groupName.empty() || !pdi.folderGroupObj->isEmpty<side>())) //don't show for missing folders
++ (groupName.empty() || !pdi.folderGroupObj->isEmpty<side>())) //don't show for missing folders
{
tryDrawNavMarker(rectGroupParent);
-@@ -950,7 +1018,7 @@ private:
- drawCellText(dc, rectGroupParentText, groupParentFolder, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, &getTextExtentBuffered(dc, groupParentFolder));
+
+ wxRect rectGroupParentText = rectGroupParent;
+ rectGroupParentText.x += gapSize_;
+- rectGroupParentText.width -= gapSize_;
+- drawCellText(dc, rectGroupParentText, groupParentPart, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, &getTextExtentBuffered(dc, groupParentPart));
++ rectGroupParentText.width -= stackedGroupRender ? gapSize_ + gapSizeWide_ : gapSize_;
++
++ drawCellText(dc, rectGroupParentText, groupParentFolder, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, &getTextExtentBuffered(dc, groupParentFolder));
}
-- if (!groupName.empty() &&
+- if (!groupName.empty())
+ if (!(itemPathFormat_ == ItemPathFormat::traditional || itemPathFormat_ == ItemPathFormat::tradrel) && !groupName.empty() &&
- row == groupFirstRow)
++ row == groupFirstRow)
{
wxRect rectGroupNameBack = rectGroupName;
-@@ -1142,7 +1210,13 @@ private:
- groupNameWidth] = getGroupRenderLayout(dc, row, pdi, insanelyHugeWidth);
- assert(!stackedGroupRender);
-- const int groupSepWidth = (groupParentFolder.empty() && groupName.empty()) ? 0 : (2 * gapSize_ + dipToWxsize(1));
+@@ -1047,7 +1064,7 @@
+ if (!itemName.empty())
+ {
+ //draw group/items separation line
+- if (rectGroup.width > 0)
++ if (!groupParentFolder.empty() || !groupName.empty())
+ {
+ rectGroupItems.x += 2 * gapSize_;
+ rectGroupItems.width -= 2 * gapSize_;
+@@ -1150,15 +1167,18 @@
+ if (const FileView::PathDrawInfo pdi = getDataView().getDrawInfo(row);
+ pdi.fsObj)
+ {
+- const auto& [groupParentPart,
++ const auto& [itemName,
+ groupName,
+- itemName,
++ groupParentFolder,
++ groupFirstRow,
++ stackedGroupRender,
+ groupParentWidth,
+- groupNameWidth] = getGroupRowLayout(dc, row, pdi, cellWidth);
++ groupNameWidth] = getGroupRenderLayout(dc, row, pdi, cellWidth);
+
+- if (!groupName.empty() && pdi.fsObj != pdi.folderGroupObj)
++ if (!groupName.empty() && row == groupFirstRow && pdi.fsObj != pdi.folderGroupObj)
+ {
+- const int groupNameCellBeginX = groupParentWidth;
++ const int groupNameCellBeginX = (stackedGroupRender ? std::max(groupParentWidth, groupNameWidth) - groupNameWidth : //right-aligned
++ groupParentWidth); //group details on single row
+
+ if (groupNameCellBeginX <= cellRelativePosX && cellRelativePosX < groupNameCellBeginX + groupNameWidth + 2 * gapSize_ /*include gap before vline*/)
+ return static_cast<HoverArea>(HoverAreaGroup::groupName);
+@@ -1181,13 +1201,22 @@
+ /* ________________________ ___________________________________ _____________________________________________________
+ | (gap | group parent) | | (gap | icon | gap | group name) | | (2x gap | vline) | (gap | icon) | gap | item name |
+ ------------------------ ----------------------------------- ----------------------------------------------------- */
+- const auto& [groupParentPart,
++ const auto& [itemName,
+ groupName,
+- itemName,
++ groupParentFolder,
++ groupFirstRow,
++ stackedGroupRender,
+ groupParentWidth,
+- groupNameWidth] = getGroupRowLayout(dc, row, pdi, insanelyHugeWidth);
++ groupNameWidth] = getGroupRenderLayout(dc, row, pdi, insanelyHugeWidth);
++ assert(!stackedGroupRender);
++
+ // trad patch section for removing lines around items in grid
+ int lineWidth { dipToWxsize(1) } ;
+ if (itemPathFormat_ == ItemPathFormat::traditional || itemPathFormat_ == ItemPathFormat::tradrel)
+ lineWidth = 0;
+
+ const int groupSepWidth = (groupParentFolder.empty() && groupName.empty()) ? 0 : (2 * gapSize_ + lineWidth);
-+
+
+- const int groupSepWidth = groupParentWidth + groupNameWidth <= 0 ? 0 : (2 * gapSize_ + dipToWxsize(1));
const int fileIconWidth = getIconManager().getIconBuffer() ? gapSize_ + getIconManager().getIconWxsize() : 0;
const int ellipsisWidth = getTextExtentBuffered(dc, ELLIPSIS).x;
const int itemWidth = itemName.empty() ? 0 :
-@@ -1174,6 +1248,10 @@ private:
+@@ -1219,6 +1248,10 @@
return _("Relative path");
case ItemPathFormat::full:
return _("Full path");
@@ -185,7 +592,19 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
}
assert(false);
break;
-@@ -1431,6 +1509,7 @@ private:
+@@ -1341,11 +1374,6 @@
+ const std::wstring bslashBidi_ = (wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ? RTL_MARK : LTR_MARK) + std::wstring(L"\\");
+ //no need for LTR/RTL marks on both sides: text follows main direction if slash is between two strong characters with different directions
+
+- const std::wstring rightArrowDown_ = wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ?
+- std::wstring() + RTL_MARK + LEFT_ARROW_ANTICLOCK :
+- std::wstring() + LTR_MARK + RIGHT_ARROW_CURV_DOWN;
+- //Windows bug: RIGHT_ARROW_CURV_DOWN rendering and extent calculation is buggy (see wx+\tooltip.cpp) => need LTR mark!
+-
+ std::vector<int> groupItemNamesWidthBuf_; //buffer! groupItemNamesWidths essentially only depends on (groupIdx, side)
+ uint64_t viewUpdateIdLast_ = 0; //
+ };
+@@ -1481,6 +1509,7 @@
GridData::renderRowBackgound(dc, rect, row, true /*enabled*/, true /*selected*/, rowHover);
//----------------------------------------------------------------------------------
@@ -193,7 +612,7 @@ Message: restore a traditional view to FreeFileSync, and disable "welcomeShownVe
const wxRect rectLine(rect.x, rect.y + rect.height - dipToWxsize(1), rect.width, dipToWxsize(1));
clearArea(dc, rectLine, row == pdi.groupLastRow - 1 /*last group item*/ ?
getColorGridLine() : getDefaultBackgroundColorAlternating(pdi.groupIdx % 2 != 0));
-@@ -1455,6 +1534,7 @@ private:
+@@ -1505,6 +1534,7 @@
{
wxRect rectBack = rect;
if (row == pdi.groupLastRow - 1 /*last group item*/) //preserve the group separation line!
diff --git a/freefilesync/debian/patches/series b/freefilesync/debian/patches/series
index 2459055..4415360 100644
--- a/freefilesync/debian/patches/series
+++ b/freefilesync/debian/patches/series
@@ -7,10 +7,10 @@ ffs_sftp.patch
libssh2_relax_dep.patch
libcurl_improve_supported_error_codes.patch
ffs_gcc.patch
-ffs_traditional_view.patch
ffs_desktop_notifications.patch
ffs_icon_loader.patch
ffs_tooltips_no_taskbar.patch
disable_wxuse_Exceptions.patch
# makefile-improvements mostly combines wx-config-version, zlib-dep, pkg-config patches from bastif
makefile-improvements.patch
+ffs_traditional_view.patch
bgstack15