diff options
Diffstat (limited to 'freefilesync')
-rw-r--r-- | freefilesync/debian/_service | 2 | ||||
-rw-r--r-- | freefilesync/debian/changelog | 11 | ||||
-rw-r--r-- | freefilesync/debian/freefilesync+stackrpms.dsc | 2 | ||||
-rw-r--r-- | freefilesync/debian/patches/ffs_traditional_view.patch | 501 | ||||
-rw-r--r-- | freefilesync/debian/patches/series | 2 |
5 files changed, 474 insertions, 44 deletions
diff --git a/freefilesync/debian/_service b/freefilesync/debian/_service index ab08497..246f59f 100644 --- a/freefilesync/debian/_service +++ b/freefilesync/debian/_service @@ -14,7 +14,7 @@ <service name="tar_scm"> <param name="scm">git</param> <param name="url">https://gitlab.com/opensource-tracking/FreeFileSync.git</param> - <param name="revision">13.4</param> + <param name="revision">13.5</param> <param name="version">_none_</param> </service> <service name="recompress"> diff --git a/freefilesync/debian/changelog b/freefilesync/debian/changelog index 1288ac1..32f4f34 100644 --- a/freefilesync/debian/changelog +++ b/freefilesync/debian/changelog @@ -1,3 +1,14 @@ +freefilesync (13.5-100+stackrpms) obs; urgency=low + + * Upstream updates + * Wrap file grid folder paths instead of truncate + * Fixed sync operation arrows for RTL layout + * Fixed FTP hang during connection (libcurl regression) + * Consider user-defined file time tolerance for DB comparisons + * Don't log folder pair paths if nothing to sync + + -- B. Stack <bgstack15@gmail.com> Tue, 02 Apr 2024 09:25:10 -0400 + freefilesync (13.4-100+stackrpms) obs; urgency=low * Upstream updates diff --git a/freefilesync/debian/freefilesync+stackrpms.dsc b/freefilesync/debian/freefilesync+stackrpms.dsc index 69374ec..86acbd1 100644 --- a/freefilesync/debian/freefilesync+stackrpms.dsc +++ b/freefilesync/debian/freefilesync+stackrpms.dsc @@ -2,7 +2,7 @@ Format: 3.0 (quilt) Source: freefilesync Binary: freefilesync Architecture: any -Version: 13.4-101+stackrpms +Version: 13.5-100+stackrpms Maintainer: B. Stack <bgstack15@gmail.com> Homepage: https://freefilesync.org/ Standards-Version: 4.1.4 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 |