Browse Source

first commit

lennlouis 1 week ago
commit
b7a55c9676

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+.idea/
+cmake-build-*
+build/

+ 60 - 0
CMakeLists.txt

@@ -0,0 +1,60 @@
+cmake_minimum_required(VERSION 3.29)
+project(qt_ant_ui)
+
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+set(CMAKE_PREFIX_PATH "C:/Qt6/6.7.3/mingw_64")
+
+find_package(Qt6 COMPONENTS
+        Core
+        Gui
+        Widgets
+        REQUIRED)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/QAntButton/QAntAbstractButton
+        ${CMAKE_CURRENT_SOURCE_DIR}/QAntButton/QAntPrimaryButton
+)
+
+add_executable(qt_ant_ui main.cpp
+        QAntButton/QAntAbstractButton/QAntAbstractButton.cpp
+        QAntButton/QAntAbstractButton/QAntAbstractButton.h
+        QAntButton/QAntPrimaryButton/QAntPrimaryButton.cpp
+        QAntButton/QAntPrimaryButton/QAntPrimaryButton.h
+)
+target_link_libraries(qt_ant_ui
+        Qt::Core
+        Qt::Gui
+        Qt::Widgets
+)
+
+if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+    set(DEBUG_SUFFIX)
+    if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
+        set(DEBUG_SUFFIX "d")
+    endif ()
+    set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")
+    if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
+        set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
+        if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
+            set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
+        endif ()
+    endif ()
+    if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
+        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+                COMMAND ${CMAKE_COMMAND} -E make_directory
+                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
+        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+                COMMAND ${CMAKE_COMMAND} -E copy
+                "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
+                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
+    endif ()
+    foreach (QT_LIB Core Gui Widgets)
+        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
+                COMMAND ${CMAKE_COMMAND} -E copy
+                "${QT_INSTALL_PATH}/bin/Qt6${QT_LIB}${DEBUG_SUFFIX}.dll"
+                "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
+    endforeach (QT_LIB)
+endif ()

+ 262 - 0
QAntButton/QAntAbstractButton/QAntAbstractButton.cpp

@@ -0,0 +1,262 @@
+//
+// Created by Louis on 25-4-1.
+//
+
+#include "QAntAbstractButton.h"
+
+QAntAbstractButton::QAntAbstractButton(QWidget *parent) {
+	// 接收悬停事件
+	setAttribute(Qt::WA_Hover);
+	// 设置布局方案
+	setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
+}
+
+QAntAbstractButton::~QAntAbstractButton() = default;
+
+QString QAntAbstractButton::text() const {
+	return m_text;
+}
+
+void QAntAbstractButton::setText(const QString &text) {
+	if (text != m_text) {
+		m_text = text;
+		update();
+		emit textChanged(text);
+	}
+}
+
+QIcon QAntAbstractButton::icon() const {
+	return m_icon;
+}
+
+void QAntAbstractButton::setIcon(const QIcon &icon) {
+	if (icon.cacheKey() != m_icon.cacheKey()) {
+		m_icon = icon;
+		update();
+		emit iconChanged(icon);
+	}
+}
+
+QSize QAntAbstractButton::iconSize() const {
+	return m_iconSize;
+}
+
+void QAntAbstractButton::setIconSize(const QSize &size) {
+	if (m_iconSize != size) {
+		m_iconSize = size;
+		updateGeometry();
+		update();
+	}
+}
+
+QMargins QAntAbstractButton::padding() const {
+	return m_padding;
+}
+
+void QAntAbstractButton::setPadding(const QMargins &margins) {
+	if (m_padding != margins) {
+		m_padding = margins;
+		updateGeometry();
+		update();
+	}
+}
+
+QAntAbstractButton::ButtonState QAntAbstractButton::currentState() const {
+	return m_state;
+}
+
+void QAntAbstractButton::paintText(QPainter &painter, const QRect &textRect) {
+	painter.save();
+	painter.setPen(palette().color(foregroundRole()));
+	painter.setFont(font());
+	painter.drawText(textRect, Qt::AlignCenter, m_text);
+	painter.restore();
+}
+
+void QAntAbstractButton::paintIcon(QPainter &painter, const QRect &iconRect) {
+	QIcon::Mode mode = QIcon::Normal;
+	if (!isEnabled()) {
+		mode = QIcon::Disabled;
+	}
+	else if (m_state == PressedState) {
+		mode = QIcon::Selected;
+	}
+
+	m_icon.paint(&painter, iconRect, Qt::AlignCenter, mode);
+}
+
+void QAntAbstractButton::paintFocusIndicator(QPainter &painter) {
+	painter.save();
+	QPen pen(palette().highlight(), 1, Qt::DotLine);
+	painter.setPen(pen);
+	painter.setBrush(Qt::NoBrush);
+	painter.drawRect(rect().adjusted(1, 1, -1, -1));
+	painter.restore();
+}
+
+void QAntAbstractButton::paintBackground(QPainter &painter) {
+	painter.fillRect(rect(), palette().window());
+}
+
+void QAntAbstractButton::paintBorder(QPainter &painter) {
+	painter.save();
+	QPen pen(palette().shadow(), 1);
+	painter.setPen(pen);
+	painter.setBrush(Qt::NoBrush);
+	painter.drawRect(rect().adjusted(0, 0, -1, -1));
+	painter.restore();
+}
+
+QRect QAntAbstractButton::calculateTextRect(const QRect &contentsRect) const {
+	QFontMetrics fm(font());
+	QRect textRect = fm.boundingRect(contentsRect, Qt::AlignCenter, m_text);
+
+	if (!m_icon.isNull()) {
+		textRect.moveLeft(contentsRect.left() + m_iconSize.width() + 4);
+	}
+
+	return textRect;
+}
+
+QRect QAntAbstractButton::calculateIconRect(const QRect &contentsRect) const {
+	return QRect(contentsRect.left(), contentsRect.center().y() - m_iconSize.height() / 2,
+		m_iconSize.width(), m_iconSize.height());
+}
+
+void QAntAbstractButton::paintEvent(QPaintEvent *event) {
+	Q_UNUSED(event);
+
+	QPainter painter(this);
+
+	paintBackground(painter);
+
+	switch (m_state) {
+		case NormalState:
+			paintNormalState(painter);
+			break;
+		case HoverState:
+			paintHoverState(painter);
+			break;
+		case PressedState:
+			paintPressedState(painter);
+			break;
+		case DisabledState:
+			paintDisabledState(painter);
+			break;
+		case LoadingState:
+			paintLoadingState(painter);
+			break;
+	}
+
+	paintBorder(painter);
+
+	QRect contentsRect = rect().marginsRemoved(m_padding);
+
+	if (!m_icon.isNull() && m_state != LoadingState) {
+		QRect iconRect = calculateIconRect(contentsRect);
+		paintText(painter, iconRect);
+	}
+
+	if (!m_text.isEmpty() && m_state != LoadingState) {
+		QRect textRect = calculateTextRect(contentsRect);
+		paintText(painter, textRect);
+	}
+
+	if (hasFocus()) {
+		paintFocusIndicator(painter);
+	}
+}
+
+void QAntAbstractButton::mousePressEvent(QMouseEvent *event) {
+	if (event->button() == Qt::LeftButton && !m_loading && isEnabled()) {
+		m_mousePressed = true;
+		updateButtonState(PressedState);
+		emit pressed();
+		event->accept();
+	}
+}
+
+void QAntAbstractButton::mouseReleaseEvent(QMouseEvent *event) {
+	if (m_mousePressed && event->button() == Qt::LeftButton) {
+		m_mousePressed = false;
+
+		if (rect().contains(event->pos())) {
+			emit clicked();
+			updateButtonState(HoverState);
+		}
+		else {
+			updateButtonState(NormalState);
+		}
+	}
+	emit release();
+	event->accept();
+}
+
+void QAntAbstractButton::mouseMoveEvent(QMouseEvent *event) {
+	if (m_mousePressed) {
+		if (rect().contains(event->pos())) {
+			updateButtonState(PressedState);
+		}
+		else {
+			QWidget::mouseMoveEvent(event);
+		}
+	}
+}
+
+void QAntAbstractButton::enterEvent(QEnterEvent *event) {
+	if (isEnabled() && !m_loading && !m_mousePressed) {
+		updateButtonState(HoverState);
+	}
+	QWidget::enterEvent(event);
+}
+
+void QAntAbstractButton::leaveEvent(QEvent *event) {
+	if (isEnabled() && !m_loading) {
+		updateButtonState(NormalState);
+	}
+	QWidget::leaveEvent(event);
+}
+
+void QAntAbstractButton::focusInEvent(QFocusEvent *event) {
+	update();
+	QWidget::focusInEvent(event);
+}
+
+void QAntAbstractButton::focusOutEvent(QFocusEvent *event) {
+	update();
+	QWidget::focusOutEvent(event);
+}
+
+void QAntAbstractButton::changeEvent(QEvent *event) {
+	if (event->type() == QEvent::EnabledChange) {
+		if (isEnabled()) {
+			updateButtonState(NormalState);
+		}
+		else {
+			updateButtonState(DisabledState);
+		}
+		emit enabledChanged(isEnabled());
+	}
+	QWidget::changeEvent(event);
+}
+
+void QAntAbstractButton::updateButtonState(ButtonState newState) {
+	if (newState == m_state)
+		return;
+
+	ButtonState oldState = m_state;
+	m_state = newState;
+
+	animateStateChange(oldState, m_state);
+
+	update();
+}
+
+void QAntAbstractButton::animateStateChange(ButtonState oldState, ButtonState newState) {
+	Q_UNUSED(oldState);
+	Q_UNUSED(newState);
+}
+
+
+
+

+ 94 - 0
QAntButton/QAntAbstractButton/QAntAbstractButton.h

@@ -0,0 +1,94 @@
+//
+// Created by Louis on 25-4-1.
+//
+
+#ifndef QANTABSTRACTBUTTON_H
+#define QANTABSTRACTBUTTON_H
+#include <qwidget.h>
+#include <qpainter.h>
+#include <qicon.h>
+#include <qtimer.h>
+#include <qevent.h>
+#include <qfontmetrics.h>
+
+class QAntAbstractButton : public QWidget{
+	Q_OBJECT
+public:
+	enum ButtonState {
+		NormalState,
+		HoverState,
+		PressedState,
+		DisabledState,
+		LoadingState
+	};
+
+	Q_ENUM(ButtonState)
+
+	explicit QAntAbstractButton(QWidget* parent = nullptr);
+	virtual ~QAntAbstractButton();
+
+	QString text() const;
+	void setText(const QString& text);
+
+	QIcon icon() const;
+	void setIcon(const QIcon& icon);
+
+	QSize iconSize() const;
+	void setIconSize(const QSize& size);
+
+	QMargins padding() const;
+	void setPadding(const QMargins& margins);
+
+	ButtonState currentState() const;
+
+signals:
+	void clicked();
+	void pressed();
+	void release();
+	void textChanged(const QString& text);
+	void iconChanged(const QIcon& icon);
+	void enabledChanged(bool enabled);
+	void loadingChanged(bool loading);
+
+protected:
+	virtual void paintNormalState(QPainter& painter) = 0;
+	virtual void paintHoverState(QPainter& painter) = 0;
+	virtual void paintPressedState(QPainter& painter) = 0;
+	virtual void paintDisabledState(QPainter& painter) = 0;
+	virtual void paintLoadingState(QPainter& painter) = 0;
+
+	virtual void paintText(QPainter& painter, const QRect& textRect);
+	virtual void paintIcon(QPainter& painter, const QRect& iconRect);
+	virtual void paintFocusIndicator(QPainter& painter);
+	virtual void paintBackground(QPainter& painter);
+	virtual void paintBorder(QPainter& painter);
+
+	virtual QRect calculateTextRect(const QRect& contentsRect) const;
+	virtual QRect calculateIconRect(const QRect& contentsRect) const;
+
+	void paintEvent(QPaintEvent* event) override;
+	void mousePressEvent(QMouseEvent *event) override;
+	void mouseReleaseEvent(QMouseEvent *event) override;
+	void mouseMoveEvent(QMouseEvent *event) override;
+	void enterEvent(QEnterEvent *event) override;
+	void leaveEvent(QEvent *event) override;
+	void focusInEvent(QFocusEvent *event) override;
+	void focusOutEvent(QFocusEvent *event) override;
+	void changeEvent(QEvent *) override;
+
+	void updateButtonState(ButtonState newState);
+	void animateStateChange(ButtonState oldState, ButtonState newState);
+
+private:
+	QString m_text;
+	QIcon m_icon;
+	QSize m_iconSize = QSize(16, 16);
+	QMargins m_padding = QMargins(8, 4, 8, 4);
+	ButtonState m_state = NormalState;
+
+	bool m_loading = false;
+	bool m_mousePressed = false;
+	bool m_hasFocus = false;
+};
+
+#endif //QANTABSTRACTBUTTON_H

+ 5 - 0
QAntButton/QAntPrimaryButton/QAntPrimaryButton.cpp

@@ -0,0 +1,5 @@
+//
+// Created by Louis on 25-4-1.
+//
+
+#include "QAntPrimaryButton.h"

+ 35 - 0
QAntButton/QAntPrimaryButton/QAntPrimaryButton.h

@@ -0,0 +1,35 @@
+//
+// Created by Louis on 25-4-1.
+//
+
+#ifndef QANTPRIMARYBUTTON_H
+#define QANTPRIMARYBUTTON_H
+
+#include "QAntAbstractButton.h"
+
+class QAntPrimaryButton : public QAntAbstractButton{
+	Q_OBJECT
+
+public:
+	explicit QAntPrimaryButton(QWidget* parent = nullptr);
+
+	QColor normalColor() const;
+	void setNormalColor(const QColor& color);
+
+	QColor hoverColor() const;
+	void setHoverColor(const QColor& color);
+
+	QColor pressedColor() const;
+	void setPressedColor(const QColor& color);
+
+	QColor disabledColor() const;
+	void setDisabledColor(const QColor& color);
+
+	QColor textColor() const;
+	void setTextColor(const QColor& color);
+	
+};
+
+
+
+#endif //QANTPRIMARYBUTTON_H

+ 13 - 0
main.cpp

@@ -0,0 +1,13 @@
+#include <QApplication>
+#include <QPushButton>
+#include "QAntAbstractButton.h"
+#include <QtCore/QStringConverter>
+
+int main(int argc, char *argv[]) {
+	QApplication a(argc, argv);
+	// QPushButton button("Hello world!", nullptr);
+	QAntAbstractButton button;
+	// button.resize(200, 100);
+	// button.show();
+	return QApplication::exec();
+}