first commit

This commit is contained in:
2026-02-21 17:11:31 +09:00
commit 18b4338361
4001 changed files with 365464 additions and 0 deletions

View File

@@ -0,0 +1,714 @@
#include "fm_thumbnail_dialog.h"
//#include "fm_thumbnail.h"
#if (RM_MODEL == RM_MODEL_TYPE_TB4000)
#include <QFileInfo>
#include <QGridLayout>
#include "../data/rm_video_list.h"
#include "../data/rm_video_item_2ch.h"
#include "../core/rm_math.h"
#include "fm_button.h"
#include <QLabel>
#include <QRunnable>
#include <QScrollArea>
#include <QApplication>
#include <QResizeEvent>
#include <QStyleOption>
#include <QPainter>
#include <QPushButton>
#include <QDir>
#include <QShortcut>
#include <QTableWidget>
#include <QHeaderView>
#include <QMainWindow>
#include <QtConcurrent>
#if (DETECT_USB_CHANGE)
#include "../core/rm_usb.h"
#endif // #if (DETECT_USB_CHANGE)
int g_thumbnail_dialog_width = 814;
int g_thumbnail_dialog_height = 600;
int g_thumbnail_column_count = 4;
const int g_thumbnail_row_count = 4; // 표시 줄...
const int g_thumbnail_title_height = 22; // 타이틀 높이
const int g_thumbnail_width = 200;
const int g_thumbnail_height = (int)((double)g_thumbnail_width / 480.0 * 320.0);
const int g_thumbnail_border_size = 4; // 선택영역 처리 ETC
const bool g_dual_ch_thumbnail = true; // 전후방 모두 처리
//const int td_width = 1024;
#if (USE_DATE_FILTER)
QStringList FMThumbnailDialog::_files = QStringList();
#endif // #if (USE_DATE_FILTER)
#if (USE_1HOUR_FILTER)
QList<QPair<QString,QString>> FMThumbnailDialog::_thumbnails = QList<QPair<QString,QString>>();
QList<RMVideoItem*> FMThumbnailDialog::_items = QList<RMVideoItem*>();
#endif
QRect rectAspectFit(QRect src,int w, int h) {
int l = src.left();
int t = src.top();
if(src.width() > w )
{
l += (src.width() - w) / 2;
}
if(src.height() > h )
{
t += (src.height() - h) / 2;
}
return QRect(l,t,w,h);
}
FM_COLOR_SET g_thumb_button_colors[5] = {
0x595959, // normal
0x2e2e2e, // pressed
0x343434, // hover
0x595959, // disabled
0x3a3a3a, // checked
};
void FMThumbnailDialog::closeEvent(QCloseEvent *event)
{
/*
// accept, reject 호출되지 않음
//qInfo() << playItems << __FUNCTION__;
selectedItem = NULL;
if(FMThumbnailLoader::bRunning) {
FMThumbnailLoader::bStop = true;
event->ignore();
#if !(THUMBNAIL_ITEM_CONNECT_EACH)
for(int i=0;i<_items.size();i++) {
disconnect(_items.at(i),SIGNAL(thumnbnailsLoaded(RMVideoItem*)),this,SLOT(onThumbnailLoaded(RMVideoItem*)));
// for(int j=0;j<_items.at(i)->thumbnails.size();j++)
// {
// FMThumbnail* thumbnail = _items.at(i)->thumbnails.at(j);
// total += thumbnail->size;
// delete _items.at(i)->thumbnails.at(j);
// }
// _items.at(i)->thumbnails.clear();
}
#endif // THUMBNAIL_ITEM_CONNECT_EACH
// 강제 종료 후 연결
FMThumbnailSignal::instance()->mode = FMThumbnailSignal::MODE_REJECT; // 종료 모드
connect(FMThumbnailSignal::instance(),SIGNAL(finished()),SLOT(onProcessFinished()));
}
*/
}
#if (USE_DATE_FILTER)
FMThumbnailDialog::FMThumbnailDialog(QWidget *parent, QString folder) : QDialog(parent,Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint)
#else // USE_DATE_FILTER
FMThumbnailDialog::FMThumbnailDialog(QWidget *parent, bool bAll) : QDialog(parent,Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint)
#endif // USE_DATE_FILTER
{
_bFirst = false;
_mode = MODE_SIMPLE;
#if (USE_DATE_FILTER)
_folder = folder;
#endif
if( RMApp::instance()->pMainWindow->isFullScreen()) {
int maxWidth = RMApp::instance()->pMainWindow->width() - 360;
g_thumbnail_column_count = (maxWidth / 400) * 2;
g_thumbnail_dialog_width = (g_thumbnail_column_count * 200) + 14;
g_thumbnail_dialog_height = RMApp::instance()->pMainWindow->height() - 240;
qInfo() << g_thumbnail_dialog_width << g_thumbnail_column_count << __FUNCTION__;
} else {
g_thumbnail_dialog_width = 814;
g_thumbnail_dialog_height = 600;
g_thumbnail_column_count = 4;
}
//qInfo() << "isMaximized:" << RMApp::instance()->pMainWindow->isFullScreen() << __FUNCTION__;
setFixedWidth(g_thumbnail_dialog_width+5);
resize(g_thumbnail_dialog_width+5,g_thumbnail_dialog_height);
QVBoxLayout* l = new QVBoxLayout(this);
ZERO_LAYOUT(l);
QWidget* top = new QWidget(this);
top->setStyleSheet("background-color: #595959;");
top->setFixedHeight(40);
l->addWidget(top);
QHBoxLayout* topL = new QHBoxLayout(top);
ZERO_LAYOUT(topL);
_titleBar = new QLabel(top);
_titleBar->setAlignment(Qt::AlignCenter);
_titleBar->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);
_titleBar->setStyleSheet("font-family: Malgun Gothic;font-size: 16px; color : #FFFFFF;");
topL->addWidget(_titleBar);
//_titleBar->setText(FM_WSTR(L"1시간 대표 이미지"));
_backButton = FMButton::btnType0(top,topL,"thumbnail_back",FM_WSTR(L"1시간 리스트로 돌아가기"),QSize(40,40),g_thumb_button_colors);
_backButton->setHidden(true);
//l->addWidget(_backButton);
connect(_backButton,SIGNAL(clicked()),this,SLOT(onBack()));
_tableView = new QTableWidget(this);
_tableView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
_tableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
_tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_tableView->verticalHeader()->hide();
_tableView->horizontalHeader()->hide();
_tableView->verticalHeader()->setDefaultSectionSize(g_thumbnail_height + g_thumbnail_title_height);
_tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
_tableView->horizontalHeader()->setDefaultSectionSize(g_thumbnail_width);
_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
_tableView->setAttribute(Qt::WA_Hover);
_tableView->viewport()->setAttribute(Qt::WA_Hover);
_tableView->setSelectionMode(QAbstractItemView::SingleSelection);
_tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
_tableView->setShowGrid(false);
_tableView->setObjectName("thumbnail");
_tableView->setStyleSheet("QTableWidget#thumbnail{background-color: #333333;}");
_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
_delegate = new FMThumbnailDelegate(this);
//_tableView->setItemDelegate(_delegate);
l->addWidget(_tableView);
// 배경색만 바꿈..
connect(_tableView->selectionModel(),SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),this,SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &)));
createLayout(MODE_SIMPLE);
connect(thumbnail_cache::instance(),SIGNAL(thumbnailLoaded(int)),this,SLOT(onThumbnailUpdated(int)));
if(bAll) {
_mode = MODE_SUB;
}
QTimer::singleShot(100,Qt::PreciseTimer,this,SLOT(onLoadThumbnails()));
connect(_tableView, SIGNAL(cellDoubleClicked(int,int)), this, SLOT(onDoubleClickItem(int,int)));
#if (DETECT_USB_CHANGE)
connect(RMApp::instance()->usb,SIGNAL(usbChanged(bool,QString&)),SLOT(onUSBChange(bool,QString&)));
#endif // DETECT_USB_CHANGE
}
#if (DETECT_USB_CHANGE)
void FMThumbnailDialog::onUSBChange(bool inserted, QString& drive)
{
// 제거시 리스트 삭제
if(!inserted && drive.toUpper() == _usb->_openDrive) {
reject();
}
}
#endif // #if (DETECT_USB_CHANGE)
void FMThumbnailDialog::showEvent(QShowEvent * event)
{
Q_UNUSED(event)
_tableView->setItemDelegate(_delegate);
}
void FMThumbnailDialog::onThumbnailUpdated(int index)
{
int row_start = qMax(_tableView->verticalHeader()->visualIndexAt(0), 0);
int row_end = _tableView->verticalHeader()->visualIndexAt(_tableView->verticalHeader()->height());
if(row_end == -1) {
row_end = _tableView->rowCount() - 1;
}
if (index >= row_start && index <= row_end) {
_tableView->viewport()->update();
//qInfo() << "row_start:" << row_start << index << "row_end:" << row_end << "loaded";
}
}
void FMThumbnailDialog::scrollTo()
{
if(_lastIndex.isValid()) {
_tableView->setItemDelegate(_delegate);
_tableView->scrollTo(_lastIndex); // ,QTableView::PositionAtTop
_lastIndex = QModelIndex();
}
}
void FMThumbnailDialog::onDoubleClickItem(int row, int column)
{
if(_mode == MODE_SIMPLE) {
return;
}
int idx = ((row * g_thumbnail_column_count) + column) / 2;
bool ch1 = column % 2 == 0;// ? " - [CH1]" : " - [CH2]";
selectedFile = _items.at(idx)->filePath;// ch1 ? FMThumbnailDialog::_thumbnails.at(idx).first : FMThumbnailDialog::_thumbnails.at(idx).second;
accept();
//qInfo() << "idx:" << idx << selectedFile << __FUNCTION__;
}
void FMThumbnailDialog::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
//qInfo() << __FUNCTION__;
QModelIndex index = selected.indexes().first();
int idx = ((index.row() * g_thumbnail_column_count) + index.column()) / 2;
// bool ch1 = index.column() % 2 == 0;// ? " - [CH1]" : " - [CH2]"; // 더블클릭 재생으로 이동
#if (USE_DATE_FILTER)
selectedFile = FMThumbnailDialog::_files.at((idx * 2) + (ch1 ? 0 : 1));
accept();
#endif // USE_DATE_FILTER
#if (USE_1HOUR_FILTER)
if (FMThumbnailDialog::_thumbnails.size() <= idx) {
return;
}
if(_mode == MODE_SIMPLE) {
RMVideoItem* item = FMThumbnailDialog::_items.at(idx);
_selectedDateTime = item->startTime();
_mode = MODE_SUB;
onLoadThumbnails();
_tableView->setEnabled(false);
QTimer::singleShot(300,Qt::PreciseTimer,this,SLOT(onEnableClick()));
} else {
// 더블클릭 재생으로 변경
//selectedFile = ch1 ? FMThumbnailDialog::_thumbnails.at(idx).first : FMThumbnailDialog::_thumbnails.at(idx).second;
//accept();
}
#endif
}
void FMThumbnailDialog::onEnableClick()
{
_tableView->setEnabled(true);
}
void FMThumbnailDialog::createLayout(MODE mode,RMVideoItem* selected)
{
}
#if (USE_DATE_FILTER)
void FMThumbnailDialog::loadThumbnails(QString folder)
{
thumbnail_cache::instance()->clear();
QDir dir(folder);
dir.setFilter(QDir::Dirs);
foreach (const QString& eachFolder, dir.entryList()) {
if(eachFolder == "." || eachFolder == "..")
{
continue;
}
// 폴더는 탐색
QString fullPath = QDir::cleanPath(folder + PATH_COMPONENT + eachFolder);
loadThumbnails(fullPath);
}
QDir dirFile(folder);
dirFile.setNameFilters(QList<QString>() << QString("*.JPG"));
QStringList allFiles = dirFile.entryList();
foreach (const QString& eachFile, allFiles) {
//QDateTime dateTime;
QString fullPath = QDir::cleanPath(folder + PATH_COMPONENT + eachFile);
QRegExp regexp("[0-9]{8}-[0-9]{6}_(?:REC|MOT|PSR|EVT)[0,1,2]_[0-9]{4}_[0-9]{1}.jpg"); // $
//QRegExp regexp("[0-9]{8}-[0-9]{6}_(?:REC|EVT)_[0-9]{4}_[0-9]{1}.jpg"); // $
if(regexp.exactMatch(eachFile)) {
_files.append(fullPath);
//qInfo() << eachFile << __FUNCTION__;
}
}
}
void FMThumbnailDialog::onLoadThumbnails()
{
_files.clear();
_tableView->setItemDelegate(NULL);
loadThumbnails(_folder);
qSort(_files.begin(),_files.end());
int itemCount = _files.size(); // 파일개수
int rowCount = qMax((int)ceil((double)(itemCount) / ((double)g_thumbnail_column_count)),g_thumbnail_row_count);
//_tableView->clear();
_tableView->setItemDelegate(_delegate);
_tableView->setColumnCount(g_thumbnail_column_count);
_tableView->setRowCount(rowCount); // ON LOADED 에서 처리
//qInfo() << __FUNCTION__;
}
#else // USE_DATE_FILTER
void FMThumbnailDialog::loadThumbnails()
{
FMThumbnailDialog::_items.clear();
//QList<RMVideoItem*> res = QList<RMVideoItem*>();
// 1시간 단위
if(_mode == MODE_SIMPLE) {
RMVideoFileList::instance()->load1HourList(_items);
} else {
RMVideoFileList::instance()->load1HourInList(_selectedDateTime,_items);
}
RMVideoFileList::instance()->loadThumbnails(_items,_thumbnails);
}
void FMThumbnailDialog::onLoadThumbnails()
{
// 선택해제하지 않으면 이후 이전 선택된 CELL 선택이 안됨
_tableView->selectionModel()->blockSignals(true);
_tableView->clearSelection();
_tableView->selectionModel()->blockSignals(false);
_tableView->setItemDelegate(NULL);
loadThumbnails();
int itemCount = FMThumbnailDialog::_thumbnails.size() * 2;// 0;//_files.size(); // 파일개수
int rowCount = qMax((int)ceil((double)(itemCount) / ((double)g_thumbnail_column_count)),g_thumbnail_row_count);
_tableView->setItemDelegate(_delegate);
_tableView->setColumnCount(g_thumbnail_column_count);
_tableView->setRowCount(rowCount); // ON LOADED 에서 처리
_backButton->setHidden(_mode == MODE_SIMPLE);
QString wTitle = "";
QString barTitle = "";
if(_mode == MODE_SIMPLE) {
barTitle = FM_WSTR(L"1시간 대표 이미지");
wTitle = FM_WSTR(L"1시간리스트 (이미지 클릭 시 1시간내 전체 이미지를 볼 수 있습니다.)");
} else {
wTitle = FM_WSTR(L"세부리스트 (이미지 더블 클릭 시 해당 영상이 재생됩니다.)");
QString title = _items.first()->startTime().toString("yyyy-MM-dd HH:mm:ss");
title += " ~ ";
title += _items.last()->startTime().toString("yyyy-MM-dd HH:mm:ss");
barTitle = title;
}
_titleBar->setText(barTitle + QString().sprintf(" [%d]",_items.size()));
//setWindowTitle(wTitle + QString().sprintf(" [%d]",_items.size()));
setWindowTitle(wTitle);
}
void FMThumbnailDialog::onBack() {
_mode = MODE_SIMPLE;
onLoadThumbnails();
}
#endif // USE_DATE_FILTER
FMThumbnailDelegate::FMThumbnailDelegate(QObject *parent) :
QStyledItemDelegate(parent)
{
_dialog = (FMThumbnailDialog*)parent;
}
#if (USE_DATE_FILTER)
void FMThumbnailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QRect rect = option.rect;
painter->fillRect(rect,QColor(0x33,0x33,0x33));
//qInfo() << rect << index << index.column() << __FUNCTION__;
painter->setRenderHint(QPainter::NonCosmeticDefaultPen); // Antialiasing
int idx = ((index.row() * g_thumbnail_column_count) + index.column()) / 2;
bool ch1 = index.column() % 2 == 0;// ? " - [CH1]" : " - [CH2]";
// _dialog->_items.size()
bool drawItem = true;
// if(_dialog->_loadedCount <= idx) {
// drawItem = false;
// }
if(drawItem) {
//RMVideoItem* item = _dialog->_items.at(idx);
//qInfo() << idx << __FUNCTION__;
QString p1 = FMThumbnailDialog::_files.at((idx * 2) + (ch1 ? 0 : 1));
//painter->fillRect(option.rect,background);
QFont font = QFont("Arial", 1);
font.setPixelSize(12);
painter->setFont(font);
QRect tr = QRect(rect.left()+1,rect.bottom()-g_thumbnail_title_height,rect.width(),g_thumbnail_title_height);
//tr.adjust(0,tr.height() - g_thumbnail_title_height,0,- g_thumbnail_title_height);
//tr.setHeight(g_thumbnail_height);
painter->fillRect(tr,QColor(0x33,0x33,0x33)); // "#333333"
QFileInfo fi(p1);
painter->setPen(QPen(QColor(0xDD,0xDD,0xDD))); // "#DDDDDD"
painter->drawText(tr, Qt::AlignCenter | Qt::AlignVCenter, fi.baseName());
//qInfo() << "TR:" << tr << "RECT:" << rect.size() << __LINE__;
//QPixmap map;
if (fi.exists()) {
QRect ir = rect;
ir.adjust(0,0,-0,-g_thumbnail_title_height);
//int iid = (index.row() * g_thumbnail_column_count) + index.column();
QPixmap pix = thumbnail_cache::instance()->thumbnail(p1,index.row(),ir.size());
if (!pix.isNull()) {
painter->drawPixmap(rectAspectFit(ir,pix.width(),pix.height()),pix);
}
// if(p1.contains("040556_PSR0_0017_") || p1.contains("040536_PSR0_0016_")) {
// qInfo() << "DRAW:" << p1 << ir << __FUNCTION__;
// }
// painter->scale(1*((double)(ir.width())/(double)(map.width())),1*((double)(ir.height())/(double)(map.height())));
// painter->scale(1,1);
}
// IR: QRect(0,166 254x143) PIX SIZE: QSize(247, 138) RECT: QRect(0,166 254x165) 930
/*
if(thumbnails.size() > 1) {
QRect ir = rect;
ir.adjust(0,0,-0,-g_thumbnail_title_height);
//ir.adjust(g_thumbnail_border_size,g_thumbnail_border_size,-g_thumbnail_border_size,-(g_thumbnail_title_height+g_thumbnail_border_size));
FMThumbnail* thumb = item->thumbnails.at(ch1 ? 0 : 1);
//qInfo() << thumb->size << __FUNCTION__;
if(thumb->size == 0) {
painter->fillRect(ir,QColor(0x11,0x11,0x11));// "#111111"
painter->drawText(ir, Qt::AlignCenter | Qt::AlignVCenter, QString::fromWCharArray(L"로딩 실패"));
}
else {
QPixmap pix;
pix.loadFromData(thumb->buffer,thumb->size);
painter->drawPixmap(ir,pix);
}
}
*/
}
// 외곽선 그리기
QPen pen2; // c5ff5f
pen2.setJoinStyle(Qt::MiterJoin);
pen2.setColor(QColor(0xd0,0xd5,0xef)); // d0d5ef,b8bee0
pen2.setWidth(4);
painter->setPen(pen2);
QLine lines[3];
int al = rect.left()+1;
int ar = rect.right() - (ch1 ? 0 : 1);
int at = rect.top()+1;
int ab = rect.bottom();
lines[0] = !ch1 ? QLine(al,at,ar,at) : QLine(ar,at,al,at);
lines[1] = !ch1 ? QLine(ar,at,ar,ab) : QLine(al,at,al,ab);
lines[2] = !ch1 ? QLine(ar,ab,al,ab) : QLine(al,ab,ar,ab);
painter->drawLines(lines,3);
// GRID LINE
pen2.setColor(QColor(0x31,0x33,0x4A)); // fcc186,31334a
pen2.setWidth(1);
painter->setPen(pen2);
if(!ch1) {
painter->drawLine(QLine(ar+1,at,ar+1,ab));
}
//painter->drawLine(QLine(al-1,ab,ar,ab));
if(drawItem) {
bool hover = option.state & QStyle::State_MouseOver;
if (hover) {
//qInfo() << "STATE:" << QString().sprintf("%0X",(int)option.state) << __FUNCTION__;
int iw = g_thumbnail_border_size / 2;
QRect br = rect;
br.adjust(iw,iw,-iw,-iw);
QPen pen; // c5ff5f
pen.setJoinStyle(Qt::MiterJoin);
pen.setColor(QColor(0xFF,0x99,0x33)); // "#FF9933"
pen.setWidth(g_thumbnail_border_size);
painter->setPen(pen);
//QPalette palette = _checkContainerWidget->palette();
//palette.setColor(_checkContainerWidget->backgroundRole(),background);
//qInfo() << "index:" << index << "option:" << option.rect << __FUNCTION__;
painter->drawRect(br);// fillRect(r, QColor(0,0,0,10));
}
}
}
#else // #if (USE_DATE_FILTER)
void FMThumbnailDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QRect rect = option.rect;
painter->fillRect(rect,QColor(0x33,0x33,0x33));
painter->setRenderHint(QPainter::NonCosmeticDefaultPen); // Antialiasing
int idx = ((index.row() * g_thumbnail_column_count) + index.column()) / 2;
bool ch1 = index.column() % 2 == 0;// ? " - [CH1]" : " - [CH2]";
if(FMThumbnailDialog::_thumbnails.size() <= idx) {
return;
}
bool drawItem = true;
if(drawItem) {
QString p1 = ch1 ? FMThumbnailDialog::_thumbnails.at(idx).first : FMThumbnailDialog::_thumbnails.at(idx).second;
//painter->fillRect(option.rect,background);
QFont font = QFont("Arial", 1);
font.setPixelSize(12);
painter->setFont(font);
QRect tr = QRect(rect.left()+1,rect.bottom()-g_thumbnail_title_height,rect.width(),g_thumbnail_title_height);
//tr.adjust(0,tr.height() - g_thumbnail_title_height,0,- g_thumbnail_title_height);
//tr.setHeight(g_thumbnail_height);
painter->fillRect(tr,QColor(0x33,0x33,0x33)); // "#333333"
QFileInfo fi(p1);
painter->setPen(QPen(QColor(0xDD,0xDD,0xDD))); // "#DDDDDD"
//painter->drawText(tr, Qt::AlignCenter | Qt::AlignVCenter, fi.baseName());
if(ch1) {
painter->drawText(tr, Qt::AlignRight | Qt::AlignVCenter, fi.baseName().left(8));
} else {
painter->drawText(tr, Qt::AlignLeft | Qt::AlignVCenter, fi.baseName().mid(8, 7));
}
//qInfo() << "TR:" << tr << "RECT:" << rect.size() << __LINE__;
//QPixmap map;
QRect ir = rect;
ir.adjust(0,0,-0,-g_thumbnail_title_height);
QPixmap pix;
//int iid = (index.row() * g_thumbnail_column_count) + index.column();
if (fi.exists()) {
pix = thumbnail_cache::instance()->thumbnail(p1,index.row(),ir.size());
} else {
static QPixmap no_image;
// 200,133
//qInfo() << ir.size() << __FUNCTION__;
if(no_image.isNull()) {
QPixmap ni = QPixmap(":/image/no_thumbnail.png");
if(ni.width() != ir.size().width() || ni.height() != ir.size().width()) {
no_image = ni.scaled(ir.size().width(),ir.size().width(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
} else {
no_image = ni;
}
}
pix = no_image;
}
if (!pix.isNull()) {
painter->drawPixmap(rectAspectFit(ir,pix.width(),pix.height()),pix);
}
}
// 외곽선 그리기
QPen pen2; // c5ff5f
pen2.setJoinStyle(Qt::MiterJoin);
pen2.setColor(QColor(0xd0,0xd5,0xef)); // d0d5ef,b8bee0
pen2.setWidth(4);
painter->setPen(pen2);
QLine lines[3];
int al = rect.left()+1;
int ar = rect.right() - (ch1 ? 0 : 1);
int at = rect.top()+1;
int ab = rect.bottom();
lines[0] = !ch1 ? QLine(al,at,ar,at) : QLine(ar,at,al,at);
lines[1] = !ch1 ? QLine(ar,at,ar,ab) : QLine(al,at,al,ab);
lines[2] = !ch1 ? QLine(ar,ab,al,ab) : QLine(al,ab,ar,ab);
painter->drawLines(lines,3);
// GRID LINE
pen2.setColor(QColor(0x31,0x33,0x4A)); // fcc186,31334a
pen2.setWidth(1);
painter->setPen(pen2);
if(!ch1) {
painter->drawLine(QLine(ar+1,at,ar+1,ab));
}
//painter->drawLine(QLine(al-1,ab,ar,ab));
if(drawItem) {
bool hover = option.state & QStyle::State_MouseOver;
if (hover) {
//qInfo() << "STATE:" << QString().sprintf("%0X",(int)option.state) << __FUNCTION__;
int iw = g_thumbnail_border_size / 2;
QRect br = rect;
br.adjust(iw,iw,-iw,-iw-g_thumbnail_title_height);
QPen pen; // c5ff5f
pen.setJoinStyle(Qt::MiterJoin);
pen.setColor(QColor(0xFF,0x99,0x33)); // "#FF9933"
pen.setWidth(g_thumbnail_border_size);
painter->setPen(pen);
painter->drawRect(br);// fillRect(r, QColor(0,0,0,10));
}
}
}
#endif // #else // #if (USE_DATE_FILTER)
void FMThumbnailDelegate::entered(const QModelIndex &index)
{
qInfo() << index << __FUNCTION__ << __LINE__;
}
thumbnail_cache::thumbnail_cache(QObject* parent) : QObject(parent)
{
}
QPixmap thumbnail_cache::_load(QString path, const QSize& wh)
{
QPixmap map;
map.load(path);
// 1:1 이미지 CROP
if((float)map.width() / (float)map.height() < 1.1) {
// 16:9 = 1.7777
qreal wr = (qreal)wh.width() / (qreal)wh.height(); // 1.7777
//qreal tw = wr; // 0.88888
int width = map.width();
int height = map.height() / wr;
// 50% 크롭 영역 계산 (가운데 50%만 남기기)
// 시작점은 너비와 높이의 25% 지점
// 잘라낼 영역의 너비와 높이는 원본의 50%
//int cropHeight = height * 0.5;
//int cropWidth = cropHeight * wr;
int yOffset = (map.width() - height) / 2;
//int xOffset = (width - cropWidth) / 2;
//qInfo() << "wh:" << wh << "width:" << width << "height:" << height << "X:" << xOffset << cropWidth << "Y:" << yOffset << cropHeight;
map = map.copy(QRect(0, yOffset, width, height));
}
// resize
if(map.width() > wh.width() || map.height() > wh.height())
{
map = map.scaled(wh.width(),wh.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
}
return map;
}
const QPixmap thumbnail_cache::thumbnail(const QString path,int index, const QSize& wh)
{
// 존재할 경우 리턴
if(cache.contains(path)) {
//qInfo() << "E" << path << __FUNCTION__;
return cache.value(path);
}
// 없으면 생성
QFuture<QPixmap> loaded = QtConcurrent::run(this,&thumbnail_cache::_load,path,wh);
cache[path] = loaded;
emit thumbnailLoaded(index);
return _dummy;
}
#endif // #if (GENERATE_THUMBNAIL)