diff --git a/win-linux/res/icons/downloading.svg b/win-linux/res/icons/downloading.svg
deleted file mode 100644
index b358e294b..000000000
--- a/win-linux/res/icons/downloading.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/win-linux/res/icons/loading.svg b/win-linux/res/icons/loading.svg
new file mode 100644
index 000000000..1f4a2b9aa
--- /dev/null
+++ b/win-linux/res/icons/loading.svg
@@ -0,0 +1,3 @@
+
diff --git a/win-linux/res/icons/loading_finished.svg b/win-linux/res/icons/loading_finished.svg
new file mode 100644
index 000000000..e94483f25
--- /dev/null
+++ b/win-linux/res/icons/loading_finished.svg
@@ -0,0 +1,4 @@
+
diff --git a/win-linux/res/icons/loading_finished_light.svg b/win-linux/res/icons/loading_finished_light.svg
new file mode 100644
index 000000000..8bc21f27c
--- /dev/null
+++ b/win-linux/res/icons/loading_finished_light.svg
@@ -0,0 +1,4 @@
+
diff --git a/win-linux/res/icons/loading_light.svg b/win-linux/res/icons/loading_light.svg
new file mode 100644
index 000000000..c575628a4
--- /dev/null
+++ b/win-linux/res/icons/loading_light.svg
@@ -0,0 +1,3 @@
+
diff --git a/win-linux/res/styles/download.qss b/win-linux/res/styles/download.qss
index 1db227a6f..4d284273a 100644
--- a/win-linux/res/styles/download.qss
+++ b/win-linux/res/styles/download.qss
@@ -1,19 +1,33 @@
-CDownloadWidget {background: #ffffff;}
-QWidget#contentArea {background: #ffffff;}
-QPushButton {padding: 0px; font-weight: normal;}
-QPushButton:hover {background-color: #cecece;}
-QPushButton:pressed {background-color: #b7b7b7;}
+CDownloadWidget {background: transparent;}
+QWidget#contentArea,
+QFrame#mainFrame,
+QFrame#titleFrame,
+QFrame#downloadItem {background: #ffffff;}
+
+QPushButton {border: none; color: #3a83db; background: transparent; padding: 0px; margin: 0px; font-weight: normal; font-family: "Open Sans", sans-serif, "Arial";}
QPushButton::menu-indicator {width: 0px; height: 0px;}
-QPushButton#buttonCancel {border: none; margin: 0px; padding: 0px; color: #666666; font-family: "Open Sans", sans-serif, "Arial";}
+QPushButton#buttonCancel {color: #ffffff;}
+QPushButton:hover {color: #444444;}
+QPushButton:pressed {color: #a5a5a5;}
-QProgressBar {background-color: #cacaca; border-color: #cacaca;}
-QProgressBar::chunk {background-color: #2b86b7;}
+QProgressBar {background-color: #e6e6e6; border-color: #e6e6e6; margin: 0px;}
+QProgressBar::chunk {background-color: #3a83db;}
-QLabel#labelName {color: #666666; font-family: "Open Sans", sans-serif, "Arial";}
+QLabel {color: #444444; font-family: "Open Sans", sans-serif, "Arial";}
+QLabel#labelSize,
+QLabel#labelInfo {color: #a5a5a5;}
-QScrollArea {border: none;}
-QScrollBar {background: transparent;}
+QFrame#downloadItem[hovered=true] {background: #e0e0e0;}
+QFrame#downloadItem[hovered=true] #buttonCancel {color: #3a83db;}
+QFrame#downloadItem[hovered=true] #buttonCancel:hover {color: #444444;}
+QFrame#downloadItem[hovered=true] #buttonCancel:pressed {color: #868686;}
+QFrame#downloadItem[hovered=true] QProgressBar {background-color: #cacaca; border-color: #cacaca;}
+QFrame#downloadItem[hovered=true] #labelSize,
+QFrame#downloadItem[hovered=true] #labelInfo {color: #868686;}
+
+QScrollArea {background: #ffffff; border: none;}
+QScrollBar {background: #ffffff;}
QScrollBar:vertical {margin: 0px; border: none; border-radius: 0px; background: transparent;}
QScrollBar::handle:vertical {background: #cacaca;}
QScrollBar::add-line:vertical {height: 10px; border: none; border-radius: 0px;
@@ -26,122 +40,184 @@ QScrollBar::add-page:vertical,
QScrollBar::sub-page:vertical {background: none;}
QAbstractScrollArea::corner {background: transparent;}
-/* dark theme */
-CDownloadWidget[uitheme="theme-dark"] {background: #404040;}
-CDownloadWidget[uitheme="theme-dark"] QWidget#contentArea {background: #404040;}
-CDownloadWidget[uitheme="theme-dark"] QPushButton#buttonCancel {color: #d9d9d9;}
-CDownloadWidget[uitheme="theme-dark"] QPushButton#buttonCancel:hover {background: #555;}
-CDownloadWidget[uitheme="theme-dark"] QPushButton#buttonCancel:pressed {background: #606060;}
-CDownloadWidget[uitheme="theme-dark"] QLabel#labelName {color: #d9d9d9;}
-
-/* contrast theme */
-CDownloadWidget[uitheme="theme-contrast-dark"] {background: #2a2a2a;}
-CDownloadWidget[uitheme="theme-contrast-dark"] QWidget#contentArea {background: #2a2a2a;}
-CDownloadWidget[uitheme="theme-contrast-dark"] QPushButton#buttonCancel {color: #d9d9d9;}
-CDownloadWidget[uitheme="theme-contrast-dark"] QPushButton#buttonCancel:hover {background: #555;}
-CDownloadWidget[uitheme="theme-contrast-dark"] QPushButton#buttonCancel:pressed {background: #606060;}
-CDownloadWidget[uitheme="theme-contrast-dark"] QLabel#labelName {color: #d9d9d9;}
-
/* 1.0x */
-QPushButton#buttonCancel {padding-left: 6px; padding-right: 6px; min-height: 22px; font-size: 12px;}
-QProgressBar {border-radius: 2px; max-height: 5px; margin-right: 10px; margin-top: 1px;}
+QPushButton {height: 14px; font-size: 11px; icon-size: 12px;}
+QPushButton#buttonClear {max-height: 22px;}
+QPushButton#buttonOpenFolder,
+QPushButton#buttonOpen {margin-top: 2px;}
+QProgressBar {border-radius: 2px; max-height: 5px; margin-top: 4px; margin-bottom: 5px;}
QProgressBar::chunk {border-radius: 2px;}
-QLabel#labelName {font-size: 16px;}
-QScrollBar:vertical {width: 10px;}
+QLabel {font-size: 11px; max-height: 14px; min-height: 14px;}
+QLabel#labelTitle {font-size: 14px; max-height: 22px;}
+QScrollBar:vertical {width: 8px;}
QScrollBar::handle:vertical {min-height: 25px; border-radius: 3px;}
+QFrame#mainFrame {border: 1px solid #d1d1d1; border-radius: 3px;}
+QFrame#titleFrame {border-bottom: 1px solid #d1d1d1; min-height: 30px;}
/* 1.25x */
-CDownloadWidget[zoom="1.25x"] QPushButton#buttonCancel {padding-left: 8px; padding-right: 8px; min-height: 28px; font-size: 15px;}
-CDownloadWidget[zoom="1.25x"] QProgressBar {border-radius: 2px; max-height: 6px; margin-right: 13px; margin-top: 1px;}
-CDownloadWidget[zoom="1.25x"] QProgressBar::chunk {border-radius: 2px;}
-CDownloadWidget[zoom="1.25x"] QLabel#labelName {font-size: 20px;}
-CDownloadWidget[zoom="1.25x"] QScrollBar:vertical {width: 13px;}
+CDownloadWidget[zoom="1.25x"] QPushButton {height: 18px; font-size: 14px; icon-size: 15px;}
+CDownloadWidget[zoom="1.25x"] QPushButton#buttonClear {max-height: 28px;}
+CDownloadWidget[zoom="1.25x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="1.25x"] QPushButton#buttonOpen {margin-top: 3px;}
+CDownloadWidget[zoom="1.25x"] QProgressBar {border-radius: 3px; max-height: 6px; margin-top: 6px; margin-bottom: 6px;}
+CDownloadWidget[zoom="1.25x"] QProgressBar::chunk {border-radius: 3px;}
+CDownloadWidget[zoom="1.25x"] QLabel {font-size: 14px; max-height: 18px; min-height: 18px;}
+CDownloadWidget[zoom="1.25x"] QLabel#labelTitle {font-size: 18px; max-height: 28px;}
+CDownloadWidget[zoom="1.25x"] QScrollBar:vertical {width: 10px;}
CDownloadWidget[zoom="1.25x"] QScrollBar::handle:vertical {min-height: 31px; border-radius: 4px;}
+CDownloadWidget[zoom="1.25x"] QFrame#mainFrame {border: 1px solid #d1d1d1; border-radius: 4px;}
+CDownloadWidget[zoom="1.25x"] QFrame#titleFrame {border-bottom: 1px solid #d1d1d1; min-height: 38px;}
/* 1.5x */
-CDownloadWidget[zoom="1.5x"] QPushButton#buttonCancel {padding-left: 9px; padding-right: 9px; min-height: 33px; font-size: 18px;}
-CDownloadWidget[zoom="1.5x"] QProgressBar {border-radius: 3px; max-height: 8px; margin-right: 15px; margin-top: 2px;}
+CDownloadWidget[zoom="1.5x"] QPushButton {height: 21px; font-size: 17px; icon-size: 18px;}
+CDownloadWidget[zoom="1.5x"] QPushButton#buttonClear {max-height: 33px;}
+CDownloadWidget[zoom="1.5x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="1.5x"] QPushButton#buttonOpen {margin-top: 3px;}
+CDownloadWidget[zoom="1.5x"] QProgressBar {border-radius: 3px; max-height: 8px; margin-top: 6px; margin-bottom: 7px;}
CDownloadWidget[zoom="1.5x"] QProgressBar::chunk {border-radius: 3px;}
-CDownloadWidget[zoom="1.5x"] QLabel#labelName {font-size: 24px;}
-CDownloadWidget[zoom="1.5x"] QScrollBar:vertical {width: 15px;}
+CDownloadWidget[zoom="1.5x"] QLabel {font-size: 17px; max-height: 21px; min-height: 21px;}
+CDownloadWidget[zoom="1.5x"] QLabel#labelTitle {font-size: 21px; max-height: 33px;}
+CDownloadWidget[zoom="1.5x"] QScrollBar:vertical {width: 12px;}
CDownloadWidget[zoom="1.5x"] QScrollBar::handle:vertical {min-height: 38px; border-radius: 5px;}
+CDownloadWidget[zoom="1.5x"] QFrame#mainFrame {border: 2px solid #d1d1d1; border-radius: 5px;}
+CDownloadWidget[zoom="1.5x"] QFrame#titleFrame {border-bottom: 2px solid #d1d1d1; min-height: 45px;}
/* 1.75x */
-CDownloadWidget[zoom="1.75x"] QPushButton#buttonCancel {padding-left: 11px; padding-right: 11px; min-height: 39px; font-size: 18px;}
-CDownloadWidget[zoom="1.75x"] QProgressBar {border-radius: 3px; max-height: 8px; margin-right: 15px; margin-top: 2px;}
-CDownloadWidget[zoom="1.75x"] QProgressBar::chunk {border-radius: 3px;}
-CDownloadWidget[zoom="1.75x"] QLabel#labelName {font-size: 24px;}
-CDownloadWidget[zoom="1.75x"] QScrollBar:vertical {width: 18px;}
+CDownloadWidget[zoom="1.75x"] QPushButton {height: 25px; font-size: 19px; icon-size: 21px;}
+CDownloadWidget[zoom="1.75x"] QPushButton#buttonClear {max-height: 39px;}
+CDownloadWidget[zoom="1.75x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="1.75x"] QPushButton#buttonOpen {margin-top: 4px;}
+CDownloadWidget[zoom="1.75x"] QProgressBar {border-radius: 4px; max-height: 9px; margin-top: 8px; margin-bottom: 8px;}
+CDownloadWidget[zoom="1.75x"] QProgressBar::chunk {border-radius: 4px;}
+CDownloadWidget[zoom="1.75x"] QLabel {font-size: 19px; max-height: 25px; min-height: 25px;}
+CDownloadWidget[zoom="1.75x"] QLabel#labelTitle {font-size: 25px; max-height: 39px;}
+CDownloadWidget[zoom="1.75x"] QScrollBar:vertical {width: 14px;}
CDownloadWidget[zoom="1.75x"] QScrollBar::handle:vertical {min-height: 44px; border-radius: 5px;}
+CDownloadWidget[zoom="1.75x"] QFrame#mainFrame {border: 2px solid #d1d1d1; border-radius: 5px;}
+CDownloadWidget[zoom="1.75x"] QFrame#titleFrame {border-bottom: 2px solid #d1d1d1; min-height: 53px;}
/* 2.0x */
-CDownloadWidget[zoom="2x"] QPushButton#buttonCancel {padding-left: 12px; padding-right: 12px; min-height: 44px; font-size: 24px;}
-CDownloadWidget[zoom="2x"] QProgressBar {border-radius: 4px; max-height: 10px; margin-right: 20px; margin-top: 2px;}
+CDownloadWidget[zoom="2x"] QPushButton {height: 28px; font-size: 22px; icon-size: 24px;}
+CDownloadWidget[zoom="2x"] QPushButton#buttonClear {max-height: 44px;}
+CDownloadWidget[zoom="2x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="2x"] QPushButton#buttonOpen {margin-top: 4px;}
+CDownloadWidget[zoom="2x"] QProgressBar {border-radius: 4px; max-height: 10px; margin-top: 9px; margin-bottom: 9px;}
CDownloadWidget[zoom="2x"] QProgressBar::chunk {border-radius: 4px;}
-CDownloadWidget[zoom="2x"] QLabel#labelName {font-size: 32px;}
-CDownloadWidget[zoom="2x"] QScrollBar:vertical {width: 20px;}
+CDownloadWidget[zoom="2x"] QLabel {font-size: 22px; max-height: 28px; min-height: 28px;}
+CDownloadWidget[zoom="2x"] QLabel#labelTitle {font-size: 28px; max-height: 44px;}
+CDownloadWidget[zoom="2x"] QScrollBar:vertical {width: 16px;}
CDownloadWidget[zoom="2x"] QScrollBar::handle:vertical {min-height: 50px; border-radius: 6px;}
+CDownloadWidget[zoom="2x"] QFrame#mainFrame {border-width: 2px; border-radius: 6px;}
+CDownloadWidget[zoom="2x"] QFrame#titleFrame {border-bottom-width: 2px; min-height: 60px;}
/* 2.25x */
-CDownloadWidget[zoom="2.25x"] QPushButton#buttonCancel {padding-left: 14px; padding-right: 14px; min-height: 50px; font-size: 27px;}
-CDownloadWidget[zoom="2.25x"] QProgressBar {border-radius: 5px; max-height: 11px; margin-right: 23px; margin-top: 2px;}
+CDownloadWidget[zoom="2.25x"] QPushButton {height: 32px; font-size: 25px; icon-size: 27px;}
+CDownloadWidget[zoom="2.25x"] QPushButton#buttonClear {max-height: 50px;}
+CDownloadWidget[zoom="2.25x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="2.25x"] QPushButton#buttonOpen {margin-top: 5px;}
+CDownloadWidget[zoom="2.25x"] QProgressBar {border-radius: 5px; max-height: 11px; margin-top: 10px; margin-bottom: 11px;}
CDownloadWidget[zoom="2.25x"] QProgressBar::chunk {border-radius: 5px;}
-CDownloadWidget[zoom="2.25x"] QLabel#labelName {font-size: 36px;}
-CDownloadWidget[zoom="2.25x"] QScrollBar:vertical {width: 23px;}
+CDownloadWidget[zoom="2.25x"] QLabel {font-size: 25px; max-height: 32px; min-height: 32px;}
+CDownloadWidget[zoom="2.25x"] QLabel#labelTitle {font-size: 32px; max-height: 50px;}
+CDownloadWidget[zoom="2.25x"] QScrollBar:vertical {width: 18px;}
CDownloadWidget[zoom="2.25x"] QScrollBar::handle:vertical {min-height: 56px; border-radius: 7px;}
+CDownloadWidget[zoom="2.25x"] QFrame#mainFrame {border: 2px solid #d1d1d1; border-radius: 7px;}
+CDownloadWidget[zoom="2.25x"] QFrame#titleFrame {border-bottom: 2px solid #d1d1d1; min-height: 68px;}
/* 2.5x */
-CDownloadWidget[zoom="2.5x"] QPushButton#buttonCancel {padding-left: 15px; padding-right: 15px; min-height: 55px; font-size: 30px;}
-CDownloadWidget[zoom="2.5x"] QProgressBar {border-radius: 5px; max-height: 13px; margin-right: 25px; margin-top: 3px;}
+CDownloadWidget[zoom="2.5x"] QPushButton {height: 35px; font-size: 28px; icon-size: 30px;}
+CDownloadWidget[zoom="2.5x"] QPushButton#buttonClear {max-height: 55px;}
+CDownloadWidget[zoom="2.5x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="2.5x"] QPushButton#buttonOpen {margin-top: 5px;}
+CDownloadWidget[zoom="2.5x"] QProgressBar {border-radius: 5px; max-height: 13px; margin-top: 11px; margin-bottom: 11px;}
CDownloadWidget[zoom="2.5x"] QProgressBar::chunk {border-radius: 5px;}
-CDownloadWidget[zoom="2.5x"] QLabel#labelName {font-size: 40px;}
-CDownloadWidget[zoom="2.5x"] QScrollBar:vertical {width: 25px;}
+CDownloadWidget[zoom="2.5x"] QLabel {font-size: 28px; max-height: 35px; min-height: 35px;}
+CDownloadWidget[zoom="2.5x"] QLabel#labelTitle {font-size: 35px; max-height: 55px;}
+CDownloadWidget[zoom="2.5x"] QScrollBar:vertical {width: 20px;}
CDownloadWidget[zoom="2.5x"] QScrollBar::handle:vertical {min-height: 63px; border-radius: 8px;}
+CDownloadWidget[zoom="2.5x"] QFrame#mainFrame {border: 3px solid #d1d1d1; border-radius: 8px;}
+CDownloadWidget[zoom="2.5x"] QFrame#titleFrame {border-bottom: 3px solid #d1d1d1; min-height: 75px;}
/* 2.75x */
-CDownloadWidget[zoom="2.75x"] QPushButton#buttonCancel {padding-left: 17px; padding-right: 17px; min-height: 61px; font-size: 33px;}
-CDownloadWidget[zoom="2.75x"] QProgressBar {border-radius: 6px; max-height: 14px; margin-right: 28px; margin-top: 3px;}
+CDownloadWidget[zoom="2.75x"] QPushButton {height: 39px; font-size: 30px; icon-size: 33px;}
+CDownloadWidget[zoom="2.75x"] QPushButton#buttonClear {max-height: 61px;}
+CDownloadWidget[zoom="2.75x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="2.75x"] QPushButton#buttonOpen {margin-top: 6px;}
+CDownloadWidget[zoom="2.75x"] QProgressBar {border-radius: 6px; max-height: 14px; margin-top: 12px; margin-bottom: 13px;}
CDownloadWidget[zoom="2.75x"] QProgressBar::chunk {border-radius: 6px;}
-CDownloadWidget[zoom="2.75x"] QLabel#labelName {font-size: 44px;}
-CDownloadWidget[zoom="2.75x"] QScrollBar:vertical {width: 28px;}
+CDownloadWidget[zoom="2.75x"] QLabel {font-size: 30px; max-height: 39px; min-height: 39px;}
+CDownloadWidget[zoom="2.75x"] QLabel#labelTitle {font-size: 39px; max-height: 61px;}
+CDownloadWidget[zoom="2.75x"] QScrollBar:vertical {width: 22px;}
CDownloadWidget[zoom="2.75x"] QScrollBar::handle:vertical {min-height: 69px; border-radius: 8px;}
+CDownloadWidget[zoom="2.75x"] QFrame#mainFrame {border: 3px solid #d1d1d1; border-radius: 8px;}
+CDownloadWidget[zoom="2.75x"] QFrame#titleFrame {border-bottom: 3px solid #d1d1d1; min-height: 83px;}
/* 3.0x */
-CDownloadWidget[zoom="3x"] QPushButton#buttonCancel {padding-left: 18px; padding-right: 18px; min-height: 66px; font-size: 36px;}
-CDownloadWidget[zoom="3x"] QProgressBar {border-radius: 6px; max-height: 15px; margin-right: 30px; margin-top: 3px;}
+CDownloadWidget[zoom="3x"] QPushButton {height: 42px; font-size: 33px; icon-size: 36px;}
+CDownloadWidget[zoom="3x"] QPushButton#buttonClear {max-height: 66px;}
+CDownloadWidget[zoom="3x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="3x"] QPushButton#buttonOpen {margin-top: 6px;}
+CDownloadWidget[zoom="3x"] QProgressBar {border-radius: 6px; max-height: 15px; margin-top: 13px; margin-bottom: 14px;}
CDownloadWidget[zoom="3x"] QProgressBar::chunk {border-radius: 6px;}
-CDownloadWidget[zoom="3x"] QLabel#labelName {font-size: 48px;}
-CDownloadWidget[zoom="3x"] QScrollBar:vertical {width: 30px;}
+CDownloadWidget[zoom="3x"] QLabel {font-size: 33px; max-height: 42px; min-height: 42px;}
+CDownloadWidget[zoom="3x"] QLabel#labelTitle {font-size: 42px; max-height: 66px;}
+CDownloadWidget[zoom="3x"] QScrollBar:vertical {width: 24px;}
CDownloadWidget[zoom="3x"] QScrollBar::handle:vertical {min-height: 75px; border-radius: 9px;}
+CDownloadWidget[zoom="3x"] QFrame#mainFrame {border: 3px solid #d1d1d1; border-radius: 9px;}
+CDownloadWidget[zoom="3x"] QFrame#titleFrame {border-bottom: 3px solid #d1d1d1; min-height: 90px;}
/* 3.5x */
-CDownloadWidget[zoom="3.5x"] QPushButton#buttonCancel {padding-left: 21px; padding-right: 21px; min-height: 77px; font-size: 42px;}
-CDownloadWidget[zoom="3.5x"] QProgressBar {border-radius: 7px; max-height: 18px; margin-right: 35px; margin-top: 4px;}
+CDownloadWidget[zoom="3.5x"] QPushButton {height: 49px; font-size: 39px; icon-size: 42px;}
+CDownloadWidget[zoom="3.5x"] QPushButton#buttonClear {max-height: 77px;}
+CDownloadWidget[zoom="3.5x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="3.5x"] QPushButton#buttonOpen {margin-top: 7px;}
+CDownloadWidget[zoom="3.5x"] QProgressBar {border-radius: 7px; max-height: 18px; margin-top: 15px; margin-bottom: 16px;}
CDownloadWidget[zoom="3.5x"] QProgressBar::chunk {border-radius: 7px;}
-CDownloadWidget[zoom="3.5x"] QLabel#labelName {font-size: 56px;}
-CDownloadWidget[zoom="3.5x"] QScrollBar:vertical {width: 35px;}
+CDownloadWidget[zoom="3.5x"] QLabel {font-size: 39px; max-height: 49px; min-height: 49px;}
+CDownloadWidget[zoom="3.5x"] QLabel#labelTitle {font-size: 49px; max-height: 77px;}
+CDownloadWidget[zoom="3.5x"] QScrollBar:vertical {width: 28px;}
CDownloadWidget[zoom="3.5x"] QScrollBar::handle:vertical {min-height: 88px; border-radius: 11px;}
+CDownloadWidget[zoom="3.5x"] QFrame#mainFrame {border: 4px solid #d1d1d1; border-radius: 11px;}
+CDownloadWidget[zoom="3.5x"] QFrame#titleFrame {border-bottom: 4px solid #d1d1d1; min-height: 105px;}
/* 4.0x */
-CDownloadWidget[zoom="4x"] QPushButton#buttonCancel {padding-left: 24px; padding-right: 24px; min-height: 88px; font-size: 48px;}
-CDownloadWidget[zoom="4x"] QProgressBar {border-radius: 8px; max-height: 20px; margin-right: 40px; margin-top: 4px;}
+CDownloadWidget[zoom="4x"] QPushButton {height: 56px; font-size: 44px; icon-size: 48px;}
+CDownloadWidget[zoom="4x"] QPushButton#buttonClear {max-height: 88px;}
+CDownloadWidget[zoom="4x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="4x"] QPushButton#buttonOpen {margin-top: 8px;}
+CDownloadWidget[zoom="4x"] QProgressBar {border-radius: 8px; max-height: 20px; margin-top: 18px; margin-bottom: 18px;}
CDownloadWidget[zoom="4x"] QProgressBar::chunk {border-radius: 8px;}
-CDownloadWidget[zoom="4x"] QLabel#labelName {font-size: 64px;}
-CDownloadWidget[zoom="4x"] QScrollBar:vertical {width: 40px;}
+CDownloadWidget[zoom="4x"] QLabel {font-size: 44px; max-height: 56px; min-height: 56px;}
+CDownloadWidget[zoom="4x"] QLabel#labelTitle {font-size: 56px; max-height: 88px;}
+CDownloadWidget[zoom="4x"] QScrollBar:vertical {width: 32px;}
CDownloadWidget[zoom="4x"] QScrollBar::handle:vertical {min-height: 100px; border-radius: 12px;}
+CDownloadWidget[zoom="4x"] QFrame#mainFrame {border: 4px solid #d1d1d1; border-radius: 12px;}
+CDownloadWidget[zoom="4x"] QFrame#titleFrame {border-bottom: 4px solid #d1d1d1; min-height: 120px;}
/* 4.5x */
-CDownloadWidget[zoom="4.5x"] QPushButton#buttonCancel {padding-left: 27px; padding-right: 27px; min-height: 99px; font-size: 54px;}
-CDownloadWidget[zoom="4.5x"] QProgressBar {border-radius: 9px; max-height: 23px; margin-right: 45px; margin-top: 5px;}
+CDownloadWidget[zoom="4.5x"] QPushButton {height: 63px; font-size: 50px; icon-size: 54px;}
+CDownloadWidget[zoom="4.5x"] QPushButton#buttonClear {max-height: 99px;}
+CDownloadWidget[zoom="4.5x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="4.5x"] QPushButton#buttonOpen {margin-top: 9px;}
+CDownloadWidget[zoom="4.5x"] QProgressBar {border-radius: 9px; max-height: 23px; margin-top: 20px; margin-bottom: 20px;}
CDownloadWidget[zoom="4.5x"] QProgressBar::chunk {border-radius: 9px;}
-CDownloadWidget[zoom="4.5x"] QLabel#labelName {font-size: 72px;}
-CDownloadWidget[zoom="4.5x"] QScrollBar:vertical {width: 45px;}
+CDownloadWidget[zoom="4.5x"] QLabel {font-size: 50px; max-height: 63px; min-height: 63px;}
+CDownloadWidget[zoom="4.5x"] QLabel#labelTitle {font-size: 63px; max-height: 99px;}
+CDownloadWidget[zoom="4.5x"] QScrollBar:vertical {width: 36px;}
CDownloadWidget[zoom="4.5x"] QScrollBar::handle:vertical {min-height: 113px; border-radius: 14px;}
+CDownloadWidget[zoom="4.5x"] QFrame#mainFrame {border: 5px solid #d1d1d1; border-radius: 14px;}
+CDownloadWidget[zoom="4.5x"] QFrame#titleFrame {border-bottom: 5px solid #d1d1d1; min-height: 135px;}
/* 5.0x */
-CDownloadWidget[zoom="5x"] QPushButton#buttonCancel {padding-left: 30px; padding-right: 30px; min-height: 110px; font-size: 60px;}
-CDownloadWidget[zoom="5x"] QProgressBar {border-radius: 10px; max-height: 25px; margin-right: 50px; margin-top: 5px;}
+CDownloadWidget[zoom="5x"] QPushButton {height: 70px; font-size: 55px; icon-size: 60px;}
+CDownloadWidget[zoom="5x"] QPushButton#buttonClear {max-height: 110px;}
+CDownloadWidget[zoom="5x"] QPushButton#buttonOpenFolder,
+CDownloadWidget[zoom="5x"] QPushButton#buttonOpen {margin-top: 10px;}
+CDownloadWidget[zoom="5x"] QProgressBar {border-radius: 10px; max-height: 25px; margin-top: 22px; margin-bottom: 23px;}
CDownloadWidget[zoom="5x"] QProgressBar::chunk {border-radius: 10px;}
-CDownloadWidget[zoom="5x"] QLabel#labelName {font-size: 80px;}
-CDownloadWidget[zoom="5x"] QScrollBar:vertical {width: 50px;}
+CDownloadWidget[zoom="5x"] QLabel {font-size: 55px; max-height: 70px; min-height: 70px;}
+CDownloadWidget[zoom="5x"] QLabel#labelTitle {font-size: 70px; max-height: 110px;}
+CDownloadWidget[zoom="5x"] QScrollBar:vertical {width: 40px;}
CDownloadWidget[zoom="5x"] QScrollBar::handle:vertical {min-height: 125px; border-radius: 15px;}
+CDownloadWidget[zoom="5x"] QFrame#mainFrame {border: 5px solid #d1d1d1; border-radius: 15px;}
+CDownloadWidget[zoom="5x"] QFrame#titleFrame {border-bottom: 5px solid #d1d1d1; min-height: 150px;}
diff --git a/win-linux/res/styles/styles.qss b/win-linux/res/styles/styles.qss
index 0273fbd64..7d12e1abb 100644
--- a/win-linux/res/styles/styles.qss
+++ b/win-linux/res/styles/styles.qss
@@ -145,7 +145,7 @@ QPushButton::menu-indicator {width: 0px; height: 0px;}
/*border-image: url(:/res/icons/menu-indicator-dark.png) 0 10 0 0 repeat repeat;*/
/*}*/
-QPushButton#toolButtonDownload {max-width: 40px; width: 40px; max-height: 28px; height: 28px;}
+QPushButton#toolButtonDownload {border-right: 1px solid #dfdfdf; max-width: 40px; width: 40px; max-height: 28px; height: 28px;}
/**************************/
/* dark theme definitions */
@@ -160,6 +160,7 @@ QPushButton#toolButtonDownload {max-width: 40px; width: 40px; max-height: 28px;
color: #d9d9d9;
}
+#mainPanel[uitheme=theme-dark] QPushButton#toolButtonDownload,
#mainPanel[uitheme=theme-dark] QPushButton#toolButtonMain {
border-right-color: #333;
}
@@ -222,6 +223,7 @@ QPushButton#toolButtonDownload {max-width: 40px; width: 40px; max-height: 28px;
background: #1e1e1e;
}
+#mainPanel[uitheme=theme-contrast-dark] QPushButton#toolButtonDownload,
#mainPanel[uitheme=theme-contrast-dark] QPushButton#toolButtonMain {
border-right-color: #1e1e1e;
}
diff --git a/win-linux/res/styles/styles@1.25x.qss b/win-linux/res/styles/styles@1.25x.qss
index 816339b8a..9ec5f21f0 100644
--- a/win-linux/res/styles/styles@1.25x.qss
+++ b/win-linux/res/styles/styles@1.25x.qss
@@ -37,7 +37,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 1px;
}
-QPushButton#toolButtonDownload {max-width: 50px; width: 50px; max-height: 35px; height: 35px;}
+QPushButton#toolButtonDownload {border-right-width: 1px; max-width: 50px; width: 50px; max-height: 35px; height: 35px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@1.5x.qss b/win-linux/res/styles/styles@1.5x.qss
index 536028f41..1b3834555 100644
--- a/win-linux/res/styles/styles@1.5x.qss
+++ b/win-linux/res/styles/styles@1.5x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 2px;
}
-QPushButton#toolButtonDownload {max-width: 60px; width: 60px; max-height: 42px; height: 42px;}
+QPushButton#toolButtonDownload {border-right-width: 2px; max-width: 60px; width: 60px; max-height: 42px; height: 42px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@1.75x.qss b/win-linux/res/styles/styles@1.75x.qss
index 683e72afb..aa533bc6d 100644
--- a/win-linux/res/styles/styles@1.75x.qss
+++ b/win-linux/res/styles/styles@1.75x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 2px;
}
-QPushButton#toolButtonDownload {max-width: 70px; width: 70px; max-height: 49px; height: 49px;}
+QPushButton#toolButtonDownload {border-right-width: 2px; max-width: 70px; width: 70px; max-height: 49px; height: 49px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@2.25x.qss b/win-linux/res/styles/styles@2.25x.qss
index d0e351a0c..a89bdd71e 100644
--- a/win-linux/res/styles/styles@2.25x.qss
+++ b/win-linux/res/styles/styles@2.25x.qss
@@ -15,7 +15,7 @@ QPushButton#toolButtonMain[theme=light] {border-width: 2px; border-bottom: 0 non
QPushButton#toolButtonMain[class=normal],
QPushButton#toolButtonMain[class=normal]:hover {border-bottom-width: 2px;}
-QPushButton#toolButtonDownload {max-width: 90px; width: 90px; max-height: 63px; height: 63px;}
+QPushButton#toolButtonDownload {border-right-width: 2px; max-width: 90px; width: 90px; max-height: 63px; height: 63px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@2.5x.qss b/win-linux/res/styles/styles@2.5x.qss
index 297905c01..1110c156f 100644
--- a/win-linux/res/styles/styles@2.5x.qss
+++ b/win-linux/res/styles/styles@2.5x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 3px;
}
-QPushButton#toolButtonDownload {max-width: 100px; width: 100px; max-height: 70px; height: 70px;}
+QPushButton#toolButtonDownload {border-right-width: 3px; max-width: 100px; width: 100px; max-height: 70px; height: 70px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@2.75x.qss b/win-linux/res/styles/styles@2.75x.qss
index 2293167c3..f713e1224 100644
--- a/win-linux/res/styles/styles@2.75x.qss
+++ b/win-linux/res/styles/styles@2.75x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 3px;
}
-QPushButton#toolButtonDownload {max-width: 110px; width: 110px; max-height: 77px; height: 77px;}
+QPushButton#toolButtonDownload {border-right-width: 3px; max-width: 110px; width: 110px; max-height: 77px; height: 77px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@2x.qss b/win-linux/res/styles/styles@2x.qss
index 65bd57e53..cc02d82c6 100644
--- a/win-linux/res/styles/styles@2x.qss
+++ b/win-linux/res/styles/styles@2x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 2px;
}
-QPushButton#toolButtonDownload {max-width: 80px; width: 80px; max-height: 56px; height: 56px;}
+QPushButton#toolButtonDownload {border-right-width: 2px; max-width: 80px; width: 80px; max-height: 56px; height: 56px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@3.5x.qss b/win-linux/res/styles/styles@3.5x.qss
index 4ab095259..f4e625d8c 100644
--- a/win-linux/res/styles/styles@3.5x.qss
+++ b/win-linux/res/styles/styles@3.5x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 4px;
}
-QPushButton#toolButtonDownload {max-width: 140px; width: 140px; max-height: 98px; height: 98px;}
+QPushButton#toolButtonDownload {border-right-width: 4px; max-width: 140px; width: 140px; max-height: 98px; height: 98px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@3x.qss b/win-linux/res/styles/styles@3x.qss
index 413e6b50f..e0a14f3d8 100644
--- a/win-linux/res/styles/styles@3x.qss
+++ b/win-linux/res/styles/styles@3x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 3px;
}
-QPushButton#toolButtonDownload {max-width: 120px; width: 120px; max-height: 84px; height: 84px;}
+QPushButton#toolButtonDownload {border-right-width: 3px; max-width: 120px; width: 120px; max-height: 84px; height: 84px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@4.5x.qss b/win-linux/res/styles/styles@4.5x.qss
index 477d0bdb5..aaf6f616c 100644
--- a/win-linux/res/styles/styles@4.5x.qss
+++ b/win-linux/res/styles/styles@4.5x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 5px;
}
-QPushButton#toolButtonDownload {max-width: 180px; width: 180px; max-height: 126px; height: 126px;}
+QPushButton#toolButtonDownload {border-right-width: 5px; max-width: 180px; width: 180px; max-height: 126px; height: 126px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@4x.qss b/win-linux/res/styles/styles@4x.qss
index 3f48a237d..14c59fb86 100644
--- a/win-linux/res/styles/styles@4x.qss
+++ b/win-linux/res/styles/styles@4x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 4px;
}
-QPushButton#toolButtonDownload {max-width: 160px; width: 160px; max-height: 112px; height: 112px;}
+QPushButton#toolButtonDownload {border-right-width: 4px; max-width: 160px; width: 160px; max-height: 112px; height: 112px;}
/* ToolTip*/
diff --git a/win-linux/res/styles/styles@5x.qss b/win-linux/res/styles/styles@5x.qss
index 38402b01b..3ed528af6 100644
--- a/win-linux/res/styles/styles@5x.qss
+++ b/win-linux/res/styles/styles@5x.qss
@@ -38,7 +38,7 @@ QPushButton#toolButtonMain[class=normal],
border-bottom-width: 5px;
}
-QPushButton#toolButtonDownload {max-width: 200px; width: 200px; max-height: 140px; height: 140px;}
+QPushButton#toolButtonDownload {border-right-width: 5px; max-width: 200px; width: 200px; max-height: 140px; height: 140px;}
/* ToolTip*/
diff --git a/win-linux/resources.qrc b/win-linux/resources.qrc
index 3416f880c..c8366e84b 100644
--- a/win-linux/resources.qrc
+++ b/win-linux/resources.qrc
@@ -7,7 +7,10 @@
res/icons/message_info.svg
res/icons/message_confirm.svg
res/icons/message_warn.svg
- res/icons/downloading.svg
+ res/icons/loading.svg
+ res/icons/loading_light.svg
+ res/icons/loading_finished.svg
+ res/icons/loading_finished_light.svg
res/icons/title/close.svg
res/icons/title/close_light.svg
res/icons/title/minimize.svg
diff --git a/win-linux/src/components/cdownloadwidget.cpp b/win-linux/src/components/cdownloadwidget.cpp
index c1aa723a6..d408cdea5 100644
--- a/win-linux/src/components/cdownloadwidget.cpp
+++ b/win-linux/src/components/cdownloadwidget.cpp
@@ -32,38 +32,54 @@
#include "components/cdownloadwidget.h"
#include "components/celipsislabel.h"
+#include "components/cmessage.h"
#include "cascapplicationmanagerwrapper.h"
+#include "utils.h"
#include
#include
#include
#include
#include
+#include
#include
+#include
+#include
#include "common/Types.h"
+#ifdef __linux__
+# include
+#endif
-#define DOWNLOAD_WIDGET_MIN_SIZE QSize(450, 250)
-#define MARGINS 6
-#define SPACING 6
+#define ICON_SIZE (QSizeF(20,20) * m_dpiRatio)
+#define SMALL_ICON_SIZE (QSizeF(12,12) * m_dpiRatio)
+#define WIDGET_MAX_WIDTH 300 * m_dpiRatio
+#define WIDGET_MAX_HEIGHT 400 * m_dpiRatio
+#define ITEM_MAX_HEIGHT 58 * m_dpiRatio
+#define MARGINS 6 * m_dpiRatio
+#define SPACING 2 * m_dpiRatio
+#define SHADOW 6 * m_dpiRatio
+#define RADIUS 3 * m_dpiRatio
using namespace NSEditorApi;
-class CDownloadWidget::CDownloadItem
+struct CDownloadWidget::CDownloadItem
{
-public:
CDownloadItem(QWidget * w)
- : _p_progress(w), _is_temp(true)
+ : widget(w), is_temp(true), is_finished(false)
{}
-
- QWidget * progress() const { return _p_progress; }
- bool is_temporary() const { return _is_temp; }
- void set_is_temporary(bool v) { _is_temp = v; }
-
-private:
- QWidget * _p_progress;
- bool _is_temp;
+ QWidget *widget;
+ bool is_temp, is_finished;
};
+static bool isCompositingEnabled()
+{
+#ifdef __linux__
+ return QX11Info::isCompositingManagerRunning();
+#else
+ return true;
+#endif
+}
+
static void polishItem(QWidget *item)
{
item->style()->polish(item);
@@ -76,37 +92,115 @@ static void polishItem(QWidget *item)
}
}
+static void onHover(QObject *obj, bool hovered) {
+ obj->setProperty("hovered", hovered);
+ if (QWidget *wgt = qobject_cast(obj)) {
+ polishItem(wgt);
+ if (QPushButton *open = wgt->findChild("buttonOpen")) {
+ if (CElipsisLabel *info = wgt->findChild("labelInfo")) {
+ info->style()->polish(info);
+ open->style()->polish(open);
+ info->setVisible(!hovered);
+ open->setVisible(hovered);
+ }
+ }
+ if (QPushButton *open_folder = wgt->findChild("buttonOpenFolder")) {
+ open_folder->style()->polish(open_folder);
+ open_folder->setVisible(hovered);
+ }
+ }
+}
+
+static QString getFileSize(const QString &filePath)
+{
+ qint64 fsize = 0;
+ QFile file(filePath);
+ if (file.open(QIODevice::ReadOnly)){
+ fsize = file.size();
+ file.close();
+ }
+ QString str;
+ if (fsize < 1024)
+ str = QString::number(fsize) + " " + QObject::tr("B");
+ else
+ if (fsize < 1024*1024)
+ str = QString::number((double)fsize/1024, 'f', 1) + " " + QObject::tr("kB");
+ else
+ str = QString::number((double)fsize/(1024*1024), 'f', 1) + " " + QObject::tr("MB");
+ return str;
+}
+
CDownloadWidget::CDownloadWidget(QWidget *parent)
- : QDialog(parent)
+ : QWidget(parent, Qt::Tool | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint)
, m_pToolButton(new CPushButton)
{
- setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
- setMinimumSize(DOWNLOAD_WIDGET_MIN_SIZE);
+ int shd = 0, rad = 0;
+ if (isCompositingEnabled()) {
+ setAttribute(Qt::WA_TranslucentBackground);
+ shd = qRound(SHADOW);
+ rad = qRound(RADIUS);
+ }
+ installEventFilter(this);
+ setLayout(new QVBoxLayout);
+ layout()->setContentsMargins(shd, shd, shd, shd);
+ layout()->setSpacing(0);
- QVBoxLayout *main_lut = new QVBoxLayout(this);
- main_lut->setContentsMargins(0, 0, 0, 0);
- main_lut->setSpacing(0);
- setLayout(main_lut);
+ m_mainFrame = new QFrame(this);
+ m_mainFrame->setObjectName("mainFrame");
+ m_mainFrame->setLayout(new QVBoxLayout);
+ m_mainFrame->layout()->setContentsMargins(0, rad, 0, rad);
+ m_mainFrame->layout()->setSpacing(0);
+ layout()->addWidget(m_mainFrame);
+ if (isCompositingEnabled()) {
+ QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(m_mainFrame);
+ shadow->setBlurRadius(16.0);
+ shadow->setColor(QColor(0, 0, 0, 80));
+ shadow->setOffset(1.0);
+ m_mainFrame->setGraphicsEffect(shadow);
+ }
- m_pArea = new QScrollArea(this);
+ int mrg_half = qRound(MARGINS/2);
+ int mrg_dbl = qRound(2 * MARGINS);
+ m_titleFrame = new QFrame(m_mainFrame);
+ m_titleFrame->setObjectName("titleFrame");
+ m_titleFrame->setLayout(new QHBoxLayout);
+ m_titleFrame->layout()->setContentsMargins(mrg_dbl, mrg_half, mrg_dbl, mrg_half);
+ m_titleFrame->layout()->setSpacing(0);
+
+ QLabel *labelTitle = new QLabel(m_titleFrame);
+ labelTitle->setObjectName("labelTitle");
+ labelTitle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ labelTitle->setText(tr("Downloads"));
+ m_titleFrame->layout()->addWidget(labelTitle);
+
+ QPushButton *clearButton = new QPushButton(tr("Clear"));
+ clearButton->setObjectName("buttonClear");
+ m_titleFrame->layout()->addWidget(clearButton);
+ connect(clearButton, &QPushButton::clicked, this, [=](){
+ clearlAll();
+ });
+ m_mainFrame->layout()->addWidget(m_titleFrame);
+
+ m_pArea = new QScrollArea(m_mainFrame);
m_pArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_pArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_pArea->setWidgetResizable(true);
+ m_pArea->setLayout(new QVBoxLayout);
+ m_pArea->layout()->setContentsMargins(0,0,0,0);
+ m_pArea->layout()->setSpacing(0);
- m_pContentArea = new QWidget(m_pArea);
+ m_pContentArea = new QWidget;
m_pContentArea->setObjectName("contentArea");
QVBoxLayout *lut = new QVBoxLayout(m_pContentArea);
- lut->setContentsMargins(MARGINS, MARGINS, MARGINS, MARGINS);
- lut->setSpacing(SPACING);
+ lut->setContentsMargins(0, 0, 0, 0);
+ lut->setSpacing(0);
m_pContentArea->setLayout(lut);
m_pArea->setWidget(m_pContentArea);
- main_lut->addWidget(m_pArea);
- m_pContentArea->setGeometry(0, 0, width(), height());
+ m_mainFrame->layout()->addWidget(m_pArea);
connect(this, &CDownloadWidget::downloadCanceled, this, [=](int id) {
AscAppManager::getInstance().CancelDownload(id);
- slot_downloadCanceled(id);
});
m_pToolButton->setObjectName("toolButtonDownload");
@@ -114,11 +208,17 @@ CDownloadWidget::CDownloadWidget(QWidget *parent)
m_pToolButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_pToolButton->setVisible(false);
connect(m_pToolButton, &QPushButton::clicked, this, [=]() {
+ polish();
show();
+ QPoint offset(-1 * MAIN_WINDOW_BORDER_WIDTH * m_dpiRatio, (TITLE_HEIGHT + MAIN_WINDOW_BORDER_WIDTH) * m_dpiRatio);
+ QPoint pos = parent->geometry().topRight() - QPoint(WIDGET_MAX_WIDTH, 0) + offset + QPoint(qRound(SHADOW - MARGINS/3), qRound(-SHADOW + MARGINS/3));
+ move(pos);
+ int prefHeight = m_mapDownloads.size() * ITEM_MAX_HEIGHT + 74 * m_dpiRatio;
+ setGeometry(QRect(pos, QSize(WIDGET_MAX_WIDTH, (prefHeight > WIDGET_MAX_HEIGHT) ? WIDGET_MAX_HEIGHT : prefHeight)));
+ activateWindow();
});
- m_pToolButton->setAnimatedIcon(":/downloading.svg");
- QSpacerItem *spacer = new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Expanding);
- lut->addSpacerItem(spacer);
+ m_pToolButton->setAnimatedIcon(AscAppManager::themes().current().isDark() ? ":/loading_light.svg" : ":/loading.svg");
+ lut->addSpacerItem(new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Expanding));
}
CDownloadWidget::~CDownloadWidget()
@@ -133,35 +233,51 @@ QPushButton * CDownloadWidget::toolButton()
QWidget * CDownloadWidget::addFile(const QString& fn, int id)
{
- QWidget * widget = new QWidget(m_pContentArea);
+ QFrame * widget = new QFrame;
+ widget->setObjectName("downloadItem");
+ widget->setAttribute(Qt::WA_Hover);
+ widget->installEventFilter(this);
+ widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
QGridLayout * grid = new QGridLayout;
+ int mrg = qRound(MARGINS);
+ int mrg_dbl = qRound(2 * MARGINS);
+ grid->setContentsMargins(mrg_dbl, mrg, mrg_dbl, mrg);
+ grid->setSpacing(qRound(SPACING));
+ widget->setLayout(grid);
CElipsisLabel * name = new CElipsisLabel(fn);
name->setObjectName("labelName");
name->setEllipsisMode(Qt::ElideRight);
name->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
- QProgressBar * progress = new QProgressBar;
- progress->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ grid->addWidget(name, 0, 0, 1, 1);
+
QPushButton * cancel = new QPushButton(tr("Cancel"));
cancel->setObjectName("buttonCancel");
cancel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
connect(cancel, &QPushButton::clicked, this, [=](){
emit downloadCanceled(id);
});
+ grid->addWidget(cancel, 0, 1, 1, 1);
+ QProgressBar * progress = new QProgressBar;
+ progress->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
progress->setTextVisible(false);
+ grid->addWidget(progress, 1, 0, 1, 2);
- grid->setColumnStretch(0, 1);
- grid->setColumnStretch(1, 0);
+ QHBoxLayout *adv_lut = new QHBoxLayout;
+ adv_lut->setObjectName("bottomLayout");
+ adv_lut->setContentsMargins(0,0,0,0);
+ adv_lut->setSpacing(qRound(4 * SPACING));
+ grid->addLayout(adv_lut, 2, 0, 1, 2);
- grid->addWidget(name, 0, 0, 1, 1);
- grid->addWidget(progress, 1, 0, 1, 1);
- grid->addWidget(cancel, 1, 1, 1, 1);
+ CElipsisLabel * info = new CElipsisLabel(QString("0 %1").arg(tr("kBps")));
+ info->setObjectName("labelInfo");
+ info->setEllipsisMode(Qt::ElideRight);
+ info->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ grid->addWidget(info, 2, 0, 1, 2);
- widget->setLayout(grid);
if (QVBoxLayout *lut = dynamic_cast(m_pContentArea->layout()))
lut->insertWidget(lut->count() - 1, widget);
- widget->show();
return widget;
}
@@ -175,10 +291,78 @@ void CDownloadWidget::downloadProcess(void * info)
std::map::iterator iter = m_mapDownloads.find(id);
if (pData->get_IsCanceled()) {
- slot_downloadCanceled(id);
+ onFinish(id);
+ if (iter != m_mapDownloads.end()) {
+ QGridLayout *lut = (QGridLayout*)iter->second->widget->layout();
+ if (QProgressBar *progress = qobject_cast(lut->itemAt(2)->widget()))
+ progress->setValue(0);
+ if (CElipsisLabel *label_info = qobject_cast(lut->itemAt(4)->widget()))
+ label_info->setText(tr("Canceled"));
+ if (QPushButton *cancel = qobject_cast(lut->itemAt(1)->widget())) {
+ cancel->disconnect();
+ cancel->setText("");
+ cancel->setIcon(QIcon(":/message_warn.svg"));
+ }
+ }
+
} else
if (pData->get_IsComplete()) {
- removeFile(iter);
+ onFinish(id);
+ if (iter != m_mapDownloads.end()) {
+ QString path = QString::fromStdWString(pData->get_FilePath());
+ QGridLayout *lut = (QGridLayout*)iter->second->widget->layout();
+ if (CElipsisLabel *label_info = qobject_cast(lut->itemAt(4)->widget())) {
+ label_info->setText(QFileInfo(path).absolutePath());
+ }
+ if (QPushButton *cancel = qobject_cast(lut->itemAt(1)->widget())) {
+ cancel->disconnect();
+ cancel->setText("");
+ cancel->setIcon(QIcon(":/message_confirm.svg"));
+ }
+ if (QProgressBar *progress = qobject_cast(lut->itemAt(2)->widget())) {
+ lut->removeWidget(progress);
+ delete progress;
+ }
+ QLabel *size_label = new QLabel;
+ size_label->setObjectName("labelSize");
+ size_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ size_label->setText(getFileSize(QString::fromStdWString(pData->get_FilePath())));
+ lut->addWidget(size_label, 1, 0, 1, 2);
+
+ if (QHBoxLayout *adv_lut = qobject_cast(lut->itemAt(2)->layout())) {
+ QPushButton *open = new QPushButton;
+ open->setObjectName("buttonOpen");
+ open->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ open->setText(tr("Open"));
+ open->hide();
+ adv_lut->addWidget(open);
+ connect(open, &QPushButton::clicked, this, [=]() {
+ hide();
+ if (CCefViewEditor::GetFileFormat(path.toStdWString()) == 0) {
+ if (!QDesktopServices::openUrl(QUrl::fromLocalFile(path)))
+ CMessage::error(parentWidget(), tr("Can't open file: ") + path);
+ } else {
+ AscAppManager::handleInputCmd({path.toStdWString()});
+#ifdef _WIN32
+ Utils::addToRecent(path.toStdWString());
+#endif
+ }
+ });
+
+ QPushButton *open_folder = new QPushButton;
+ open_folder->setObjectName("buttonOpenFolder");
+ open_folder->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ open_folder->setText(tr("Show in folder"));
+ open_folder->hide();
+ adv_lut->addWidget(open_folder);
+ connect(open_folder, &QPushButton::clicked, this, [=]() {
+ hide();
+ Utils::openFileLocation(path);
+ });
+ adv_lut->addItem(new QSpacerItem(5, 5, QSizePolicy::Expanding, QSizePolicy::Preferred));
+ }
+ }
+
} else {
if (iter == m_mapDownloads.end()) {
QString path = QString::fromStdWString(pData->get_FilePath()),
@@ -190,27 +374,31 @@ void CDownloadWidget::downloadProcess(void * info)
CDownloadItem * item = new CDownloadItem(addFile(file_name, id));
iter = m_mapDownloads.insert( std::pair(id, item) ).first;
if (!path.isEmpty()) {
- item->set_is_temporary(false);
+ item->is_temp = false;
+ onStart();
+ }
+ }
- if ( !m_pToolButton->isVisible() ) {
- m_pToolButton->setVisible(true);
+ if (iter->second) {
+ QLayout *lut = iter->second->widget->layout();
+ if (QProgressBar *progress = qobject_cast(lut->itemAt(2)->widget()))
+ progress->setValue(pData->get_Percent());
+ if (CElipsisLabel *label_info = qobject_cast(lut->itemAt(4)->widget()))
+ label_info->setText(QString("%1 %2").arg(QString::number(pData->get_Speed(), 'f', 0), tr("kBps")));
+
+ if (iter->second->is_temp) {
+ QString path = QString::fromStdWString(pData->get_FilePath());
+ if (!path.isEmpty()) {
+ if (CElipsisLabel *label_name = static_cast(lut->itemAt(0)->widget()))
+ label_name->setText(getFileName(path));
+ iter->second->is_temp = false;
+ onStart();
}
}
}
- updateProgress(iter, pData);
}
}
-void CDownloadWidget::slot_downloadCanceled(int id)
-{
- removeFile(id);
-}
-
-void CDownloadWidget::removeFile(int id)
-{
- removeFile(m_mapDownloads.find(id));
-}
-
void CDownloadWidget::removeFile(MapItem iter)
{
if (iter != m_mapDownloads.end()) {
@@ -226,38 +414,6 @@ void CDownloadWidget::removeFile(MapItem iter)
}
}
-void CDownloadWidget::updateProgress(MapItem iter, void * data)
-{
- CElipsisLabel * label_name;
- QProgressBar * progress;
- CDownloadItem * d_item;
- CAscDownloadFileInfo * pData;
-
- d_item = static_cast((*iter).second);
- if (d_item) {
- pData = reinterpret_cast(data);
- progress = qobject_cast(d_item->progress()->layout()->itemAt(1)->widget());
-
- if (progress && pData) {
- progress->setValue(pData->get_Percent());
- }
-
- if (d_item->is_temporary()) {
- QString path = QString().fromStdWString(pData->get_FilePath());
-
- if (!path.isEmpty()) {
- label_name = static_cast(d_item->progress()->layout()->itemAt(0)->widget());
- label_name->setText(getFileName(path));
- d_item->set_is_temporary(false);
-
- if ( !m_pToolButton->isVisible()) {
- m_pToolButton->setVisible(true);
- }
- }
- }
- }
-}
-
QString CDownloadWidget::getFileName(const QString& path) const
{
QFileInfo info(path);
@@ -270,9 +426,36 @@ void CDownloadWidget::closeEvent(QCloseEvent *ev)
hide();
}
+bool CDownloadWidget::eventFilter(QObject *obj, QEvent *ev)
+{
+ switch (ev->type()) {
+ case QEvent::WindowDeactivate:
+ if (obj == this)
+ hide();
+ break;
+ case QEvent::HoverEnter:
+ if (obj->objectName() == "downloadItem")
+ onHover(obj, true);
+ break;
+ case QEvent::HoverLeave:
+ if (obj->objectName() == "downloadItem")
+ onHover(obj, false);
+ break;
+ default:
+ break;
+ }
+ return QWidget::eventFilter(obj, ev);
+}
+
void CDownloadWidget::polish()
{
style()->polish(this);
+ m_mainFrame->style()->polish(m_mainFrame);
+ m_titleFrame->style()->polish(m_titleFrame);
+ if (QLabel *labelTitle = m_titleFrame->findChild("labelTitle"))
+ labelTitle->style()->polish(labelTitle);
+ if (QPushButton *buttonClear = m_titleFrame->findChild("buttonClear"))
+ buttonClear->style()->polish(buttonClear);
m_pArea->style()->polish(m_pArea);
m_pArea->verticalScrollBar()->style()->polish(m_pArea->verticalScrollBar());
m_pContentArea->style()->polish(m_pContentArea);
@@ -285,19 +468,80 @@ void CDownloadWidget::polish()
void CDownloadWidget::updateScalingFactor(double factor)
{
+ m_dpiRatio = factor;
setProperty("zoom", QString::number(factor) + "x");
- setMinimumSize(DOWNLOAD_WIDGET_MIN_SIZE * factor);
- m_pArea->verticalScrollBar()->setFixedWidth(qRound(10 * factor));
- int mrg = qRound(MARGINS * factor);
- m_pContentArea->layout()->setContentsMargins(mrg, mrg, mrg, mrg);
- m_pContentArea->layout()->setSpacing(qRound(SPACING * factor));
- m_pToolButton->setIconSize((QSizeF(20,20) * factor).toSize());
+ int shd = 0, rad = 0;
+ int mrg = qRound(MARGINS);
+ int mrg_half = qRound(MARGINS/2);
+ int mrg_dbl = qRound(2 * MARGINS);
+ if (isCompositingEnabled()) {
+ shd = qRound(SHADOW);
+ rad = qRound(RADIUS);
+ }
+ layout()->setContentsMargins(shd, shd, shd, shd);
+ m_mainFrame->layout()->setContentsMargins(0, rad, 0, rad);
+ m_titleFrame->layout()->setContentsMargins(mrg_dbl, mrg_half, mrg_dbl, mrg_half);
+ m_pArea->layout()->setContentsMargins(0, 0, 0, 0);
+ m_pArea->verticalScrollBar()->setFixedWidth(qRound(6 * factor));
+ m_pContentArea->layout()->setContentsMargins(0, 0, 0, 0);
+ for (int i = 0; i < m_pContentArea->layout()->count(); ++i) {
+ auto item = m_pContentArea->layout()->itemAt(i);
+ if (item && item->widget() && item->widget()->layout()) {
+ item->widget()->layout()->setContentsMargins(mrg_dbl, mrg, mrg_dbl, mrg);
+ item->widget()->layout()->setSpacing(qRound(SPACING));
+ if (QHBoxLayout *adv_lut = item->widget()->layout()->findChild("bottomLayout"))
+ adv_lut->setSpacing(qRound(4 * SPACING));
+ }
+ }
+ m_pToolButton->setIconSize(ICON_SIZE.toSize());
polish();
}
void CDownloadWidget::applyTheme(const QString &theme)
{
setProperty("uitheme", theme);
+ if (m_pToolButton->isStarted())
+ m_pToolButton->setAnimatedIcon(AscAppManager::themes().current().isDark() ? ":/loading_light.svg" : ":/loading.svg");
+ else
+ m_pToolButton->setStaticIcon(AscAppManager::themes().current().isDark() ? ":/loading_finished_light.svg" : ":/loading_finished.svg");
polish();
}
+void CDownloadWidget::onStart()
+{
+ if (!m_pToolButton->isVisible())
+ m_pToolButton->setVisible(true);
+
+ if (!m_pToolButton->isStarted())
+ m_pToolButton->setAnimatedIcon(AscAppManager::themes().current().isDark() ? ":/loading_light.svg" : ":/loading.svg");
+}
+
+void CDownloadWidget::onFinish(int id)
+{
+ auto iter = m_mapDownloads.find(id);
+ if (iter != m_mapDownloads.end())
+ iter->second->is_finished = true;
+
+ bool allIsCompleted = true;
+ for (auto &pair : m_mapDownloads) {
+ if (!pair.second->is_finished) {
+ allIsCompleted = false;
+ break;
+ }
+ }
+ if (allIsCompleted)
+ m_pToolButton->setStaticIcon(AscAppManager::themes().current().isDark() ? ":/loading_finished_light.svg" : ":/loading_finished.svg");
+}
+
+void CDownloadWidget::clearlAll()
+{
+ auto iter = m_mapDownloads.begin();
+ while (iter != m_mapDownloads.end()) {
+ if (iter->second->is_finished) {
+ removeFile(iter);
+ iter = m_mapDownloads.begin();
+ continue;
+ }
+ iter++;
+ }
+}
diff --git a/win-linux/src/components/cdownloadwidget.h b/win-linux/src/components/cdownloadwidget.h
index 912d4f517..97ce4ae2a 100644
--- a/win-linux/src/components/cdownloadwidget.h
+++ b/win-linux/src/components/cdownloadwidget.h
@@ -33,15 +33,15 @@
#ifndef CDOWNLOADWIDGET_H
#define CDOWNLOADWIDGET_H
-#include
+#include
#include
#include "cpushbutton.h"
-class CDownloadWidget : public QDialog
+class CDownloadWidget : public QWidget
{
Q_OBJECT
- class CDownloadItem;
+ struct CDownloadItem;
typedef std::map::const_iterator MapItem;
public:
@@ -54,26 +54,28 @@ public:
void applyTheme(const QString&);
protected:
- void removeFile(int);
- void updateProgress(MapItem, void *);
virtual void closeEvent(QCloseEvent *) final;
+ virtual bool eventFilter(QObject*, QEvent*) final;
private:
QWidget * addFile(const QString&, int);
QString getFileName(const QString&) const;
void removeFile(MapItem);
+ void onStart();
+ void onFinish(int);
+ void clearlAll();
void polish();
CPushButton * m_pToolButton = nullptr;
QScrollArea * m_pArea = nullptr;
QWidget *m_pContentArea = nullptr;
+ QFrame *m_mainFrame = nullptr,
+ *m_titleFrame = nullptr;
std::map m_mapDownloads;
+ double m_dpiRatio = 1;
signals:
void downloadCanceled(int);
-
-private slots:
- void slot_downloadCanceled(int);
};
#endif // CDOWNLOADWIDGET_H
diff --git a/win-linux/src/components/cpushbutton.cpp b/win-linux/src/components/cpushbutton.cpp
index be93692af..62fb9e2e5 100644
--- a/win-linux/src/components/cpushbutton.cpp
+++ b/win-linux/src/components/cpushbutton.cpp
@@ -32,7 +32,6 @@
#include "components/cpushbutton.h"
#include
-#include
#define ANIMATION_MS 2500
@@ -49,23 +48,37 @@ CPushButton::~CPushButton()
void CPushButton::setAnimatedIcon(const QString &path)
{
releaseSvg();
+ if (path.isEmpty())
+ return;
m_renderer = new QSvgRenderer(path, this);
m_animation = new QVariantAnimation(this);
- m_animation->setStartValue(0.0);
- m_animation->setKeyValueAt(0.5, 1.0);
- m_animation->setEndValue(0.0);
+ m_animation->setStartValue(0);
+ m_animation->setEndValue(360);
m_animation->setDuration(ANIMATION_MS);
m_animation->setLoopCount(-1);
m_animation->setEasingCurve(QEasingCurve::Linear);
connect(m_animation, &QVariantAnimation::valueChanged, this, [=](const QVariant &val) {
- double opacity = round(val.toReal() * 100) / 100;
- if (qRound(opacity * 100) % 2 == 0) // frequency limitation
- applyAnimatedIcon(opacity);
+ onSvgRepaint(val.toDouble());
});
m_animation->start(QAbstractAnimation::KeepWhenStopped);
}
+void CPushButton::setStaticIcon(const QString &path)
+{
+ releaseSvg();
+ if (path.isEmpty())
+ return;
+// m_renderer = new QSvgRenderer(path, this);
+// onSvgRepaint(0);
+ setIcon(QIcon(path));
+}
+
+bool CPushButton::isStarted()
+{
+ return m_animation && m_animation->state() == QAbstractAnimation::Running;
+}
+
void CPushButton::releaseSvg()
{
if (m_animation) {
@@ -78,19 +91,21 @@ void CPushButton::releaseSvg()
delete m_renderer, m_renderer = nullptr;
}
-void CPushButton::applyAnimatedIcon(double opacity)
+void CPushButton::onSvgRepaint(double angle)
{
if (m_renderer && m_renderer->isValid()) {
QSize icon_size = iconSize();
- QImage img(icon_size, QImage::Format_ARGB32);
- img.fill(Qt::transparent);
- QPixmap pixmap = QPixmap::fromImage(img, Qt::NoFormatConversion);
+ double offset = (double)icon_size.height()/2;
+ QPixmap pixmap(icon_size);
+ pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.setRenderHint(QPainter::Antialiasing);
- painter.setOpacity(opacity);
- m_renderer->render(&painter, QRect(QPoint(0,0), icon_size));
+ painter.translate(offset, offset);
+ painter.rotate(angle);
+ painter.translate(-offset, -offset);
+ m_renderer->render(&painter);
painter.end();
setIcon(QIcon(pixmap));
}
diff --git a/win-linux/src/components/cpushbutton.h b/win-linux/src/components/cpushbutton.h
index 264a7b294..7e48d0db4 100644
--- a/win-linux/src/components/cpushbutton.h
+++ b/win-linux/src/components/cpushbutton.h
@@ -44,10 +44,12 @@ public:
explicit CPushButton(QWidget *parent = nullptr);
~CPushButton();
void setAnimatedIcon(const QString &path);
+ void setStaticIcon(const QString &path);
+ bool isStarted();
private:
- void applyAnimatedIcon(double);
void releaseSvg();
+ void onSvgRepaint(double);
QVariantAnimation * m_animation = nullptr;
QSvgRenderer *m_renderer = nullptr;
};
diff --git a/win-linux/src/windows/cmainwindow.cpp b/win-linux/src/windows/cmainwindow.cpp
index fe8b31a88..80afb96e0 100644
--- a/win-linux/src/windows/cmainwindow.cpp
+++ b/win-linux/src/windows/cmainwindow.cpp
@@ -981,11 +981,9 @@ void CMainWindow::onDocumentDownload(void * info)
});
QHBoxLayout * layoutBtns = qobject_cast(m_boxTitleBtns->layout());
layoutBtns->insertWidget(1, m_pWidgetDownload->toolButton());
- m_pWidgetDownload->show();
m_pWidgetDownload->setStyleSheet(Utils::readStylesheets(":/styles/download.qss"));
m_pWidgetDownload->applyTheme(m_pMainPanel->property("uitheme").toString());
m_pWidgetDownload->updateScalingFactor(m_dpiRatio);
- m_pWidgetDownload->move(geometry().bottomRight() - m_pWidgetDownload->rect().bottomRight());
}
if (m_pWidgetDownload)
m_pWidgetDownload->downloadProcess(info);