From d850d1003ce5cada365b3699e7d23598eab282b0 Mon Sep 17 00:00:00 2001
From: i7-8700 <1281261856@qq.com>
Date: Tue, 10 Mar 2020 17:21:57 +0800
Subject: [PATCH] rename PageTitle to TitleBar; add PageView

---
 jlib/qt/View/PageView.cpp                    | 240 +++++++++++++++++++
 jlib/qt/View/PageView.h                      |  72 ++++++
 jlib/qt/View/{PageTitle.cpp => TitleBar.cpp} |  24 +-
 jlib/qt/View/{PageTitle.h => TitleBar.h}     |   6 +-
 jlib/qt/qt.vcxproj                           |   6 +-
 jlib/qt/qt.vcxproj.filters                   |  18 +-
 6 files changed, 343 insertions(+), 23 deletions(-)
 create mode 100644 jlib/qt/View/PageView.cpp
 create mode 100644 jlib/qt/View/PageView.h
 rename jlib/qt/View/{PageTitle.cpp => TitleBar.cpp} (84%)
 rename jlib/qt/View/{PageTitle.h => TitleBar.h} (94%)

diff --git a/jlib/qt/View/PageView.cpp b/jlib/qt/View/PageView.cpp
new file mode 100644
index 0000000..5a12356
--- /dev/null
+++ b/jlib/qt/View/PageView.cpp
@@ -0,0 +1,240 @@
+#include "PageView.h"
+#include <qlayout.h>
+#include "CheckBtn.h"
+#include "../QtUtils.h"
+#include "../QtStyleSheet.h"
+
+using namespace jlib::qt;
+
+static const int PAGE_FONT_SIZE = 24;
+
+static void center_cursor(QWidget* w) {
+	auto pt = w->mapToGlobal(w->rect().center());
+	SetCursorPos(pt.x(), pt.y());
+}
+
+
+PageView::PageView(QWidget *parent, int max_visible_pages)
+	: QWidget(parent)
+	, max_visible_pages_(max_visible_pages)
+{
+	setFixedHeight(30);
+
+	btn_left_ = new CheckBtn(this, db_left);
+	btn_left_->set_font_size(PAGE_FONT_SIZE);
+	btn_left_->setText("<");
+	connect(btn_left_, SIGNAL(sig_check(int, bool)), this, SLOT(slot_navigator_check(int, bool)));
+	connect(btn_left_, SIGNAL(sig_focus_on(int, bool)), this, SLOT(slot_focus_on(int, bool)));
+
+	btn_right_ = new CheckBtn(this, db_right);
+	btn_right_->set_font_size(PAGE_FONT_SIZE);
+	btn_right_->setText(">");
+	connect(btn_right_, SIGNAL(sig_check(int, bool)), this, SLOT(slot_navigator_check(int, bool)));
+	connect(btn_right_, SIGNAL(sig_focus_on(int, bool)), this, SLOT(slot_focus_on(int, bool)));
+
+	info_ = new QLabel(this);
+	info_->setStyleSheet(build_style(Qt::darkGray, PAGE_FONT_SIZE));
+}
+
+PageView::~PageView()
+{
+}
+
+void PageView::refresh()
+{
+	for (auto i : page_map_) {
+		i.second->deleteLater();
+	}
+
+	page_map_.clear();
+	visible_pages_.clear();
+
+	for (int i = 0; i < pages_; i++) {
+		auto chk = new CheckBtn(this, i);
+		chk->set_font_size(PAGE_FONT_SIZE);
+		chk->setText(QString::number(i + 1));
+		connect(chk, SIGNAL(sig_check(int, bool)), this, SLOT(slot_page_checked(int, bool)));
+		connect(chk, SIGNAL(sig_focus_on(int, bool)), this, SLOT(slot_focus_on(int, bool)));
+		chk->set_check(false);
+		chk->hide();
+
+		if (i < max_visible_pages_) {
+			visible_pages_.push_back(i);
+		}
+		page_map_[i] = chk;
+	}
+
+	if (pages_ > 0) {
+		cur_check_ = page_map_[0];
+		cur_check_->set_check(true);
+	}
+
+	refresh_layout();
+}
+
+void PageView::focus_head()
+{
+	center_cursor(btn_left_);
+}
+
+void PageView::focus_left()
+{
+	if (currentFocusedId == db_left) {
+		// nothing to do
+	} else if (currentFocusedId == db_right) {
+		if (visible_pages_.empty()) {
+			focus_head();
+		} else {
+			center_cursor(page_map_[visible_pages_.back()]);
+		}
+	} else {
+		if (currentFocusedId == visible_pages_.front()) {
+			focus_head();
+		} else {
+			currentFocusedId--;
+			center_cursor(page_map_[currentFocusedId]);
+		}
+	}
+
+}
+
+void PageView::focus_right()
+{
+	if (currentFocusedId == db_left) {
+		if (visible_pages_.empty()) {
+			center_cursor(btn_right_);
+		} else {
+			center_cursor(page_map_[visible_pages_.front()]);
+		}
+	} else if (currentFocusedId == db_right) {
+		// nothing to do
+	} else {
+		if (currentFocusedId == visible_pages_.back()) {
+			center_cursor(btn_right_);
+		} else {
+			currentFocusedId++;
+			center_cursor(page_map_[currentFocusedId]);
+		}
+	}
+}
+
+void PageView::click_current()
+{
+	slot_navigator_check(currentFocusedId, true);
+}
+
+void PageView::navigate_page(int page)
+{
+	if (page < 0 || page >= pages_) { return; }
+	
+	if (page < visible_pages_.front()) {
+		// 在左边不可见
+		for (int p = visible_pages_.front() - 1; p >= page; p--) {
+			visible_pages_.push_front(p);
+			page_map_[visible_pages_.back()]->hide();
+			visible_pages_.pop_back();
+		}
+		slot_page_checked(page, true);
+		refresh_layout();
+	} else if (page > visible_pages_.back()) {
+		// 在右边不可见
+		for (int p = visible_pages_.back() + 1; p <= page; p++) {
+			visible_pages_.push_back(p);
+			page_map_[visible_pages_.front()]->hide();
+			visible_pages_.pop_front();
+		}
+		slot_page_checked(page, true);
+		refresh_layout();
+	} else {
+		// 可见
+		slot_page_checked(page, true);
+	}
+
+}
+
+void PageView::refresh_layout()
+{
+	btn_left_->set_check(false);
+	btn_right_->set_check(false);
+	info_->setText(QString::fromLocal8Bit("共 %1 页").arg(pages_));
+
+	if (hbox_) {
+		delete hbox_;
+	}
+
+	hbox_ = new QHBoxLayout();
+	hbox_->setMargin(0);
+	hbox_->setSpacing(20);
+	hbox_->addStretch();
+	hbox_->addWidget(btn_left_);
+	
+	for (auto i : visible_pages_) {
+		auto chk = page_map_[i];
+		chk->show();
+		if (i == page_) {
+			chk->set_check();
+		}
+
+		hbox_->addWidget(chk);
+	}
+
+	hbox_->addWidget(btn_right_);
+	hbox_->addWidget(info_);
+	hbox_->addStretch();
+
+	setLayout(hbox_);
+}
+
+void PageView::slot_page_checked(int tag, bool is_check)
+{
+	if (!is_check) { page_map_[tag]->set_check(true); return; }
+	page_ = tag;
+
+	if (cur_check_) {
+		cur_check_->set_check(false);
+	}
+	cur_check_ = page_map_[page_];
+
+	// 2018-2-7 23:49:04 为了APP控制时高亮
+	cur_check_->set_check(true);
+
+	emit sig_page_changed(page_);
+}
+
+void PageView::slot_navigator_check(int tag, bool is_check)
+{
+	if (tag == db_left) {
+		btn_left_->set_check(false);
+		if (--page_ < 0) {
+			page_ = 0;
+			return;
+		}
+
+		if (visible_pages_.front() > page_) {
+			visible_pages_.push_front(page_);
+			page_map_[visible_pages_.back()]->hide();
+			visible_pages_.pop_back();
+		}
+	} else if (tag == db_right) {
+		btn_right_->set_check(false);
+		if (++page_ == pages_) {
+			page_ = pages_ - 1;
+			return;
+		}
+
+		if (visible_pages_.back() < page_) {
+			visible_pages_.push_back(page_);
+			page_map_[visible_pages_.front()]->hide();
+			visible_pages_.pop_front();
+		}
+	} 
+
+	slot_page_checked(page_, true);
+	refresh_layout();
+}
+
+void PageView::slot_focus_on(int tag, bool)
+{
+	currentFocusedId = tag;
+	emit sig_focus_on();
+}
diff --git a/jlib/qt/View/PageView.h b/jlib/qt/View/PageView.h
new file mode 100644
index 0000000..40befbc
--- /dev/null
+++ b/jlib/qt/View/PageView.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <QtWidgets>
+#include <vector>
+#include <list>
+#include <unordered_map>
+
+class CheckBtn;
+class PageView : public QWidget
+{
+	Q_OBJECT
+
+public:
+	PageView(QWidget *parent, int max_visible_pages = 20);
+	~PageView();
+
+	void set_pages(int pages) { pages_ = pages; page_ = 0; refresh(); }
+	void refresh();
+	int get_total_page() const { return pages_; }
+
+	void focus_head();
+	void focus_left();
+	void focus_right();
+	void click_current();
+	
+	//! 导航到某页
+	void navigate_page(int page);
+
+protected:
+	void refresh_layout();
+
+signals:
+	void sig_page_changed(int page);
+	void sig_focus_on();
+	
+private slots:
+	void slot_page_checked(int tag, bool is_check);
+	void slot_navigator_check(int tag, bool is_check);
+	void slot_focus_on(int,bool);
+
+private:
+	//! 页码总数
+	int pages_ = 0;
+	//! 当前页码
+	int page_ = 0;
+	
+	CheckBtn* btn_left_ = {};
+	CheckBtn* btn_right_ = {};
+	QLabel* info_ = {};
+
+	CheckBtn* cur_check_ = {};
+
+	QHBoxLayout* hbox_ = {};
+
+	//! 所有页码按钮
+	std::unordered_map<int, CheckBtn*> page_map_ = {};
+
+	//! 可视页码
+	std::list<int> visible_pages_ = {};
+
+	//! 当前高亮按钮
+	int currentFocusedId = db_left;
+
+	enum DirectionButton {
+		db_left = -1,
+		db_right = -2,
+	};
+
+	
+	int max_visible_pages_ = 20;
+	
+};
diff --git a/jlib/qt/View/PageTitle.cpp b/jlib/qt/View/TitleBar.cpp
similarity index 84%
rename from jlib/qt/View/PageTitle.cpp
rename to jlib/qt/View/TitleBar.cpp
index 05f9249..4d79918 100644
--- a/jlib/qt/View/PageTitle.cpp
+++ b/jlib/qt/View/TitleBar.cpp
@@ -1,4 +1,4 @@
-#include "PageTitle.h"
+#include "TitleBar.h"
 #include <QLayout>
 #include <QPixmap>
 #include <QApplication>
@@ -6,7 +6,7 @@
 
 using namespace jlib::qt;
 
-PageTitle::PageTitle(QWidget* parent, 
+TitleBar::TitleBar(QWidget* parent,
 					 QString minIcon,
 					 QString maxIcon,
 					 QString restoreIcon,
@@ -59,21 +59,21 @@ PageTitle::PageTitle(QWidget* parent,
 	lastTimeClick.start();
 }
 
-PageTitle::~PageTitle()
+TitleBar::~TitleBar()
 {
 }
 
-void PageTitle::set_title(QString title)
+void TitleBar::set_title(QString title)
 {
 	title_->setText(title);
 }
 
-void PageTitle::set_maximize_btn_visible(bool visible)
+void TitleBar::set_maximize_btn_visible(bool visible)
 {
 	visible ? maximize_->show() : maximize_->hide();
 }
 
-void PageTitle::set_maximized(bool isMax)
+void TitleBar::set_maximized(bool isMax)
 {
 	is_maximized_ = isMax;
 	if (isMax) {
@@ -85,14 +85,14 @@ void PageTitle::set_maximized(bool isMax)
 	}
 }
 
-void PageTitle::mousePressEvent(QMouseEvent* e)
+void TitleBar::mousePressEvent(QMouseEvent* e)
 {
 	if (!rect().contains(e->pos()))return;
 	is_mouse_pressed_ = true;
 	mouse_pressed_pos_ = mapToParent(e->pos());
 }
 
-void PageTitle::mouseMoveEvent(QMouseEvent* e)
+void TitleBar::mouseMoveEvent(QMouseEvent* e)
 {
 	if (!is_mouse_pressed_)return;
 	if (is_maximized_) {
@@ -103,7 +103,7 @@ void PageTitle::mouseMoveEvent(QMouseEvent* e)
 	parentWidget()->move(e->globalPos() - mouse_pressed_pos_);
 }
 
-void PageTitle::mouseReleaseEvent(QMouseEvent* e)
+void TitleBar::mouseReleaseEvent(QMouseEvent* e)
 {
 	is_mouse_pressed_ = false;
 
@@ -114,12 +114,12 @@ void PageTitle::mouseReleaseEvent(QMouseEvent* e)
 	lastTimeClick.start();
 }
 
-void PageTitle::slot_minimize()
+void TitleBar::slot_minimize()
 {
 	parentWidget()->showMinimized();
 }
 
-void PageTitle::slot_maximize_or_restore()
+void TitleBar::slot_maximize_or_restore()
 {
 	if (is_maximized_) {
 		maximize_->set_icon(maxIcon_);
@@ -134,7 +134,7 @@ void PageTitle::slot_maximize_or_restore()
 	emit sig_maximized(is_maximized_);
 }
 
-void PageTitle::slot_close()
+void TitleBar::slot_close()
 {
 	emit sig_close();
 }
diff --git a/jlib/qt/View/PageTitle.h b/jlib/qt/View/TitleBar.h
similarity index 94%
rename from jlib/qt/View/PageTitle.h
rename to jlib/qt/View/TitleBar.h
index 6696cd4..8bcc8f5 100644
--- a/jlib/qt/View/PageTitle.h
+++ b/jlib/qt/View/TitleBar.h
@@ -20,19 +20,19 @@
 //{
 
 
-class PageTitle : public QWidget
+class TitleBar : public QWidget
 {
 	Q_OBJECT
 
 public:
-	PageTitle(QWidget* parent = NULL,
+	TitleBar(QWidget* parent = NULL,
 			  QString minIcon = ":/Skin/system/min",
 			  QString maxIcon = ":/Skin/system/max",
 			  QString restoreIcon = ":/Skin/system/restore",
 			  QString closeIcon = ":/Skin/system/close",
 			  QString logoIcon = ":/Skin/favicon.png");
 
-	~PageTitle();
+	~TitleBar();
 
 public:
 	void set_title(QString title);
diff --git a/jlib/qt/qt.vcxproj b/jlib/qt/qt.vcxproj
index b23572c..2b210bf 100644
--- a/jlib/qt/qt.vcxproj
+++ b/jlib/qt/qt.vcxproj
@@ -97,15 +97,17 @@
     <ClCompile Include="View\BgColorBtn.cpp" />
     <ClCompile Include="View\CheckBtn.cpp" />
     <ClCompile Include="View\IconBtn.cpp" />
-    <ClCompile Include="View\PageTitle.cpp" />
+    <ClCompile Include="View\TitleBar.cpp" />
+    <ClCompile Include="View\PageView.cpp" />
     <ClCompile Include="View\RndButton.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="resource.h" />
+    <QtMoc Include="View\PageView.h" />
     <QtMoc Include="View\CheckBtn.h" />
     <QtMoc Include="View\BaseScrollView.h" />
     <QtMoc Include="View\RndButton.h" />
-    <QtMoc Include="View\PageTitle.h" />
+    <QtMoc Include="View\TitleBar.h" />
     <QtMoc Include="View\IconBtn.h" />
     <QtMoc Include="View\BgColorBtn.h" />
     <ClInclude Include="ErrorCode.h" />
diff --git a/jlib/qt/qt.vcxproj.filters b/jlib/qt/qt.vcxproj.filters
index de1739c..961b9f8 100644
--- a/jlib/qt/qt.vcxproj.filters
+++ b/jlib/qt/qt.vcxproj.filters
@@ -36,9 +36,6 @@
     <ClCompile Include="View\RndButton.cpp">
       <Filter>View</Filter>
     </ClCompile>
-    <ClCompile Include="View\PageTitle.cpp">
-      <Filter>View</Filter>
-    </ClCompile>
     <ClCompile Include="View\IconBtn.cpp">
       <Filter>View</Filter>
     </ClCompile>
@@ -51,6 +48,12 @@
     <ClCompile Include="View\CheckBtn.cpp">
       <Filter>View</Filter>
     </ClCompile>
+    <ClCompile Include="View\PageView.cpp">
+      <Filter>View</Filter>
+    </ClCompile>
+    <ClCompile Include="View\TitleBar.cpp">
+      <Filter>View</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="qt.h">
@@ -96,9 +99,6 @@
     <QtMoc Include="View\IconBtn.h">
       <Filter>View</Filter>
     </QtMoc>
-    <QtMoc Include="View\PageTitle.h">
-      <Filter>View</Filter>
-    </QtMoc>
     <QtMoc Include="View\RndButton.h">
       <Filter>View</Filter>
     </QtMoc>
@@ -108,5 +108,11 @@
     <QtMoc Include="View\CheckBtn.h">
       <Filter>View</Filter>
     </QtMoc>
+    <QtMoc Include="View\PageView.h">
+      <Filter>View</Filter>
+    </QtMoc>
+    <QtMoc Include="View\TitleBar.h">
+      <Filter>View</Filter>
+    </QtMoc>
   </ItemGroup>
 </Project>
\ No newline at end of file
-- 
2.18.1