diff --git a/YACReader/YACReader.pro b/YACReader/YACReader.pro index 6b8edcd1..5f26d395 100644 --- a/YACReader/YACReader.pro +++ b/YACReader/YACReader.pro @@ -7,7 +7,7 @@ DEPENDPATH += . \ release DEFINES += NOMINMAX YACREADER - +QMAKE_MAC_SDK = macosx10.11 QMAKE_MAC_SDK = macosx10.11 #load default build flags diff --git a/YACReaderLibrary/YACReaderLibrary.pro b/YACReaderLibrary/YACReaderLibrary.pro index 7039c64a..15d78d9f 100644 --- a/YACReaderLibrary/YACReaderLibrary.pro +++ b/YACReaderLibrary/YACReaderLibrary.pro @@ -14,7 +14,7 @@ INCLUDEPATH += ../common \ ./comic_vine/model DEFINES += SERVER_RELEASE NOMINMAX YACREADER_LIBRARY - +QMAKE_MAC_SDK = macosx10.11 #load default build flags include (../config.pri) diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp index d7f9911a..f46b589f 100644 --- a/YACReaderLibrary/db_helper.cpp +++ b/YACReaderLibrary/db_helper.cpp @@ -395,15 +395,17 @@ void DBHelper::updateReadingRemoteProgress(const ComicInfo &comicInfo, QSqlDatab { QSqlQuery updateComicInfo(db); updateComicInfo.prepare("UPDATE comic_info SET " - "read = :read, " - "currentPage = :currentPage, " - "hasBeenOpened = :hasBeenOpened" - " WHERE id = :id "); + "read = :read, " + "currentPage = :currentPage, " + "hasBeenOpened = :hasBeenOpened, " + "rating = :rating" + " WHERE id = :id "); updateComicInfo.bindValue(":read", comicInfo.read?1:0); updateComicInfo.bindValue(":currentPage", comicInfo.currentPage); updateComicInfo.bindValue(":hasBeenOpened", comicInfo.hasBeenOpened?1:0); updateComicInfo.bindValue(":id", comicInfo.id); + updateComicInfo.bindValue(":rating", comicInfo.rating); updateComicInfo.exec(); } @@ -417,10 +419,18 @@ void DBHelper::updateFromRemoteClient(qulonglong libraryId,const ComicInfo & com if(comic.info.hash == comicInfo.hash) { - if(comic.info.currentPage == comic.info.numPages) - comic.info.read = true; - comic.info.currentPage = comicInfo.currentPage; - comic.info.hasBeenOpened = true; + if(comicInfo.currentPage > 0) + { + if(comic.info.currentPage == comic.info.numPages) + comic.info.read = true; + + comic.info.currentPage = comicInfo.currentPage; + + comic.info.hasBeenOpened = true; + } + + if(comicInfo.rating > 0) + comic.info.rating = comicInfo.rating; DBHelper::updateReadingRemoteProgress(comic.info,db); } diff --git a/YACReaderLibrary/grid_comics_view.cpp b/YACReaderLibrary/grid_comics_view.cpp index 1fdae2ce..770921a7 100644 --- a/YACReaderLibrary/grid_comics_view.cpp +++ b/YACReaderLibrary/grid_comics_view.cpp @@ -160,12 +160,48 @@ void GridComicsView::setModel(ComicModel *model) ctxt->setContextProperty("dragManager", this); ctxt->setContextProperty("dropManager", this); + updateBackgroundConfig(); + if(model->rowCount()>0) setCurrentIndex(model->index(0,0)); } +} +void GridComicsView::updateBackgroundConfig() +{ + if(this->model == NULL) + return; + QQmlContext *ctxt = view->rootContext(); + //backgroun image configuration + bool useBackgroundImage = settings->value(USE_BACKGROUND_IMAGE_IN_GRID_VIEW, true).toBool(); + + if(useBackgroundImage) + { + float opacity = settings->value(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, 0.2).toFloat(); + float blurRadius = settings->value(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, 75).toInt(); + + ctxt->setContextProperty("backgroundImage", this->model->data(this->model->index(0, 0), ComicModel::CoverPathRole)); + ctxt->setContextProperty("backgroundBlurOpacity", opacity); + ctxt->setContextProperty("backgroundBlurRadius", blurRadius); + ctxt->setContextProperty("backgroundBlurVisible", true); + } + else + { + ctxt->setContextProperty("backgroundImage", QVariant()); + ctxt->setContextProperty("backgroundBlurOpacity", 0); + ctxt->setContextProperty("backgroundBlurRadius", 0); + ctxt->setContextProperty("backgroundBlurVisible", false); + } + +#ifdef Q_OS_MAC + ctxt->setContextProperty("cellColor", useBackgroundImage?"#99FFFFFF":"#FFFFFF"); + ctxt->setContextProperty("selectedColor", "#FFFFFF"); +#else + ctxt->setContextProperty("cellColor", useBackgroundImage?"#99212121":"#212121"); + ctxt->setContextProperty("selectedColor", "#121212"); +#endif } void GridComicsView::setCurrentIndex(const QModelIndex &index) diff --git a/YACReaderLibrary/grid_comics_view.h b/YACReaderLibrary/grid_comics_view.h index da8a894c..8a876198 100644 --- a/YACReaderLibrary/grid_comics_view.h +++ b/YACReaderLibrary/grid_comics_view.h @@ -63,6 +63,7 @@ public slots: void droppedFiles(const QList & urls, Qt::DropAction action); void droppedComicsForResortingAt(const QString & data, int index); + void updateBackgroundConfig(); protected slots: void requestedContextMenu(const QPoint & point); diff --git a/YACReaderLibrary/library_window.cpp b/YACReaderLibrary/library_window.cpp index ed13b638..e95ffc39 100644 --- a/YACReaderLibrary/library_window.cpp +++ b/YACReaderLibrary/library_window.cpp @@ -135,9 +135,9 @@ void LibraryWindow::setupUI() createActions(); doModels(); + doDialogs(); doLayout(); createToolBars(); - doDialogs(); createMenus(); navigationController = new YACReaderNavigationController(this); @@ -245,6 +245,7 @@ void LibraryWindow::doLayout() //comicsViewStack->setCurrentIndex(Flow); } else { comicsView = gridComicsView = new GridComicsView(); + connect(optionsDialog, SIGNAL(optionsChanged()), gridComicsView, SLOT(updateBackgroundConfig())); comicsViewStatus = Grid; //comicsViewStack->setCurrentIndex(Grid); } @@ -2256,6 +2257,7 @@ void LibraryWindow::toggleComicsView_delayed() libraryToolBar->updateViewSelectorIcon(icoViewsButton); #endif switchToComicsView(classicComicsView, gridComicsView = new GridComicsView()); + connect(optionsDialog, SIGNAL(optionsChanged()), gridComicsView, SLOT(updateBackgroundConfig())); comicsViewStatus = Grid; } else{ diff --git a/YACReaderLibrary/options_dialog.cpp b/YACReaderLibrary/options_dialog.cpp index 6073347f..36bde053 100644 --- a/YACReaderLibrary/options_dialog.cpp +++ b/YACReaderLibrary/options_dialog.cpp @@ -7,18 +7,6 @@ #include "yacreader_flow_config_widget.h" #include "api_key_dialog.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - FlowType flowType = Strip; @@ -30,6 +18,7 @@ OptionsDialog::OptionsDialog(QWidget * parent) QVBoxLayout * layout = new QVBoxLayout(this); QVBoxLayout * flowLayout = new QVBoxLayout; + QVBoxLayout * gridViewLayout = new QVBoxLayout(); QVBoxLayout * generalLayout = new QVBoxLayout(); QHBoxLayout * switchFlowType = new QHBoxLayout(); @@ -61,9 +50,43 @@ OptionsDialog::OptionsDialog(QWidget * parent) connect(apiKeyButton,SIGNAL(clicked()),this,SLOT(editApiKey())); + //grid view background config + useBackgroundImageCheck = new QCheckBox(tr("Enable background image")); + + opacityLabel = new QLabel(tr("Opacity level")); + + backgroundImageOpacitySlider = new QSlider(Qt::Horizontal); + backgroundImageOpacitySlider->setRange(5,100); + + blurLabel = new QLabel(tr("Blur level")); + + backgroundImageBlurRadiusSlider = new QSlider(Qt::Horizontal); + backgroundImageBlurRadiusSlider->setRange(0,100); + + QVBoxLayout * gridBackgroundLayout = new QVBoxLayout(); + gridBackgroundLayout->addWidget(useBackgroundImageCheck); + gridBackgroundLayout->addWidget(opacityLabel); + gridBackgroundLayout->addWidget(backgroundImageOpacitySlider); + gridBackgroundLayout->addWidget(blurLabel); + gridBackgroundLayout->addWidget(backgroundImageBlurRadiusSlider); + + QGroupBox * gridBackgroundGroup = new QGroupBox(tr("Background")); + gridBackgroundGroup->setLayout(gridBackgroundLayout); + + gridViewLayout->addWidget(gridBackgroundGroup); + gridViewLayout->addStretch(); + + connect(useBackgroundImageCheck, SIGNAL(clicked(bool)), this, SLOT(useBackgroundImageCheckClicked(bool))); + connect(backgroundImageOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(backgroundImageOpacitySliderChanged(int))); + connect(backgroundImageBlurRadiusSlider, SIGNAL(valueChanged(int)), this, SLOT(backgroundImageBlurRadiusSliderChanged(int))); + //end grid view background config + QWidget * comicFlowW = new QWidget; comicFlowW->setLayout(flowLayout); + QWidget * gridViewW = new QWidget; + gridViewW->setLayout(gridViewLayout); + QWidget * generalW = new QWidget; generalW->setLayout(generalLayout); generalLayout->addWidget(shortcutsBox); @@ -71,6 +94,9 @@ OptionsDialog::OptionsDialog(QWidget * parent) generalLayout->addStretch(); tabWidget->addTab(comicFlowW,tr("Comic Flow")); +#ifndef NO_OPENGL + tabWidget->addTab(gridViewW,tr("Grid view")); +#endif tabWidget->addTab(generalW,tr("General")); layout->addWidget(tabWidget); @@ -82,7 +108,6 @@ OptionsDialog::OptionsDialog(QWidget * parent) setWindowTitle(tr("Options")); this->layout()->setSizeConstraint(QLayout::SetFixedSize); - } void OptionsDialog::editApiKey() @@ -91,5 +116,44 @@ void OptionsDialog::editApiKey() d.exec(); } +void OptionsDialog::restoreOptions(QSettings * settings) +{ + YACReaderOptionsDialog::restoreOptions(settings); + bool useBackgroundImage = settings->value(USE_BACKGROUND_IMAGE_IN_GRID_VIEW, true).toBool(); + useBackgroundImageCheck->setChecked(useBackgroundImage); + backgroundImageOpacitySlider->setValue(settings->value(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, 0.2).toFloat()*100); + backgroundImageBlurRadiusSlider->setValue(settings->value(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, 75).toInt()); + + backgroundImageOpacitySlider->setVisible(useBackgroundImage); + backgroundImageBlurRadiusSlider->setVisible(useBackgroundImage); + opacityLabel->setVisible(useBackgroundImage); + blurLabel->setVisible(useBackgroundImage); +} + +void OptionsDialog::useBackgroundImageCheckClicked(bool checked) +{ + settings->setValue(USE_BACKGROUND_IMAGE_IN_GRID_VIEW, checked); + + backgroundImageOpacitySlider->setVisible(checked); + backgroundImageBlurRadiusSlider->setVisible(checked); + opacityLabel->setVisible(checked); + blurLabel->setVisible(checked); + + emit optionsChanged(); +} + +void OptionsDialog::backgroundImageOpacitySliderChanged(int value) +{ + settings->setValue(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, value/100.0); + + emit optionsChanged(); +} + +void OptionsDialog::backgroundImageBlurRadiusSliderChanged(int value) +{ + settings->setValue(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, value); + + emit optionsChanged(); +} diff --git a/YACReaderLibrary/options_dialog.h b/YACReaderLibrary/options_dialog.h index 9a2ca1bc..4b40e4c4 100644 --- a/YACReaderLibrary/options_dialog.h +++ b/YACReaderLibrary/options_dialog.h @@ -1,6 +1,8 @@ #ifndef __OPTIONS_DIALOG_H #define __OPTIONS_DIALOG_H +#include + #include "yacreader_options_dialog.h" #include "yacreader_global.h" @@ -15,6 +17,18 @@ Q_OBJECT public slots: void editApiKey(); + void restoreOptions(QSettings * settings); + + private slots: + void useBackgroundImageCheckClicked(bool checked); + void backgroundImageOpacitySliderChanged(int value); + void backgroundImageBlurRadiusSliderChanged(int value); + private: + QCheckBox * useBackgroundImageCheck; + QSlider * backgroundImageOpacitySlider; + QSlider * backgroundImageBlurRadiusSlider; + QLabel * opacityLabel; + QLabel * blurLabel; }; diff --git a/YACReaderLibrary/qml/GridComicsView.qml b/YACReaderLibrary/qml/GridComicsView.qml index 8fc075bc..14c5ac1d 100644 --- a/YACReaderLibrary/qml/GridComicsView.qml +++ b/YACReaderLibrary/qml/GridComicsView.qml @@ -2,9 +2,33 @@ import QtQuick 2.3 import QtQuick.Controls 1.2 import comicModel 1.0 +import QtGraphicalEffects 1.0 Rectangle { id: main + clip: true + + Image { + id: backgroundImg + anchors.fill: parent + source: backgroundImage + fillMode: Image.PreserveAspectCrop + smooth: true + mipmap: true + asynchronous : true + cache: false //TODO clear cache only when it is needed + opacity: 0 + visible: false + } + + FastBlur { + anchors.fill: backgroundImg + source: backgroundImg + radius: backgroundBlurRadius + opacity: backgroundBlurOpacity + visible: backgroundBlurVisible + } + color: backgroundColor width: parent.width height: parent.height @@ -25,7 +49,7 @@ Rectangle { id: cell width: grid.cellWidth height: grid.cellHeight - color: backgroundColor + color: "#00000000" Rectangle { @@ -54,7 +78,6 @@ Rectangle { color: ((dummyValue || !dummyValue) && comicsSelectionHelper.isSelectedIndex(index))?selectedColor:cellColor; border.color: ((dummyValue || !dummyValue) && comicsSelectionHelper.isSelectedIndex(index))?selectedBorderColor:borderColor; border.width: (Qt.platform.os === "osx")?1:0; - anchors.horizontalCenter: parent.horizontalCenter MouseArea { @@ -290,7 +313,7 @@ Rectangle { } } - YACReaderScrollView{ + YACReaderScrollView { id: scrollView anchors.fill: parent anchors.margins: 0 @@ -367,7 +390,7 @@ Rectangle { footer: Rectangle { //fix for the scroll issue, TODO find what causes the issue (some times the bottoms cells are hidden for the toolbar, no full scroll) height : 25 width : parent.width - color : backgroundColor + color : "#00000000" } move: Transition { diff --git a/YACReaderLibrary/qml/YACReaderScrollView.qml b/YACReaderLibrary/qml/YACReaderScrollView.qml index a8dc57ad..e951341d 100644 --- a/YACReaderLibrary/qml/YACReaderScrollView.qml +++ b/YACReaderLibrary/qml/YACReaderScrollView.qml @@ -274,8 +274,6 @@ FocusScope { onVerticalValueChanged: { if (!verticalRecursionGuard) { - //console.log(verticalDelta); - if (flickableItem.contentY < flickThreshold && verticalDelta > speedThreshold) { flickableItem.flick(ignored, Math.min(maxFlick, acceleration * verticalDelta)) } else if (flickableItem.contentY > flickableItem.contentHeight @@ -285,16 +283,13 @@ FocusScope { var absDelta = Math.abs(verticalDelta); if(verticalDelta < 0) - flickableItem.contentY = verticalValue + Math.min(98,0.93*absDelta+4.5); + flickableItem.contentY = Math.min(verticalMaximumValue, verticalValue + Math.min(98,0.93*absDelta+4.5)); else - flickableItem.contentY = verticalValue - Math.min(98,0.93*absDelta+4.5); -} - - - //TODO: snap to row - + flickableItem.contentY = Math.max(0, verticalValue - Math.min(98,0.93*absDelta+4.5)); } + flickableItem.contentY = Math.min(verticalMaximumValue, Math.max(0, flickableItem.contentY)); + } } onHorizontalValueChanged: { diff --git a/YACReaderLibrary/server/controllers/synccontroller.cpp b/YACReaderLibrary/server/controllers/synccontroller.cpp index 7c4c1859..6756fa3f 100644 --- a/YACReaderLibrary/server/controllers/synccontroller.cpp +++ b/YACReaderLibrary/server/controllers/synccontroller.cpp @@ -23,12 +23,13 @@ void SyncController::service(HttpRequest &request, HttpResponse &response) qulonglong libraryId; qulonglong comicId; int currentPage; + int currentRating; QString hash; foreach(QString comicInfo, data) { QList comicInfoProgress = comicInfo.split("\t"); - if(comicInfoProgress.length() == 4) + if(comicInfoProgress.length() == 4 || comicInfoProgress.length() == 5) { libraryId = comicInfoProgress.at(0).toULongLong(); comicId = comicInfoProgress.at(1).toULongLong(); @@ -39,6 +40,14 @@ void SyncController::service(HttpRequest &request, HttpResponse &response) info.currentPage = currentPage; info.hash = hash; //TODO remove the hash check and add UUIDs for libraries info.id = comicId; + + //Client 2.1+ version + if(comicInfoProgress.length() > 4) + { + currentRating = comicInfoProgress.at(4).toInt(); + info.rating = currentRating; + } + DBHelper::updateFromRemoteClient(libraryId,info); } } diff --git a/common/comic.cpp b/common/comic.cpp index e4a45ee7..f5d8734a 100644 --- a/common/comic.cpp +++ b/common/comic.cpp @@ -15,6 +15,17 @@ #include "QsLog.h" +enum YACReaderPageSortingMode +{ + YACReaderNumericalSorting, + YACReaderHeuristicSorting, + YACReaderAlphabeticalSorting +}; + +void comic_pages_sort(QList & pageNames, YACReaderPageSortingMode sortingMode); + + + const QStringList Comic::imageExtensions = QStringList() << "*.jpg" << "*.jpeg" << "*.png" << "*.gif" << "*.tiff" << "*.tif" << "*.bmp" << "*.webp"; const QStringList Comic::literalImageExtensions = QStringList() << "jpg" << "jpeg" << "png" << "gif" << "tiff" << "tif" << "bmp" << "webp"; @@ -511,7 +522,9 @@ void FileComic::process() _loaded = true; _cfi=0; - qSort(_fileNames.begin(),_fileNames.end(), naturalSortLessThanCI); + + //TODO, add a setting for choosing the type of page sorting used. + comic_pages_sort(_fileNames, YACReaderHeuristicSorting); if(_firstPage == -1) _firstPage = bm->getLastPage(); @@ -587,7 +600,8 @@ void FolderComic::process() //d.setSorting(QDir::Name|QDir::IgnoreCase|QDir::LocaleAware); QFileInfoList list = d.entryInfoList(); - qSort(list.begin(),list.end(),naturalSortLessThanCIFileInfo); + //don't fix double page files sorting, because the user can see how the SO sorts the files in the folder. + std::sort(list.begin(),list.end(),naturalSortLessThanCIFileInfo); int nPages = list.size(); _pages.clear(); @@ -825,3 +839,167 @@ Comic * FactoryComic::newComic(const QString & path) return NULL; } + + +bool is_double_page(const QString & pageName, const QString & commonPrefix, const int maxExpectedDoublePagesNumberLenght) +{ + if(pageName.startsWith(commonPrefix)) + { + QString substringContainingPageNumbers = pageName.mid(commonPrefix.length()); + QString pageNumbersSubString; + for(int i = 0 ; i < substringContainingPageNumbers.length() && substringContainingPageNumbers.at(i).isDigit(); i++) + pageNumbersSubString.append(substringContainingPageNumbers.at(i)); + + if(pageNumbersSubString.length() < 3 || pageNumbersSubString.length() > maxExpectedDoublePagesNumberLenght || pageNumbersSubString.length() % 2 == 1) + return false; + + int leftPageNumber = pageNumbersSubString.left(pageNumbersSubString.length() / 2).toInt(); + int rightPageNumber = pageNumbersSubString.mid(pageNumbersSubString.length() / 2).toInt(); + + if(leftPageNumber == 0 || rightPageNumber == 0) + return false; + + if((rightPageNumber - leftPageNumber) == 1) + return true; + } + + return false; +} + +QString get_most_common_prefix(const QList & pageNames) +{ + if(pageNames.isEmpty()) + return ""; + + QMap frequency; + int currentPrefixLenght = pageNames.at(0).split('/').last().length(); + int currentPrefixCount = 1; + + int i; + QString previous; + QString current; + for(i = 1; i < pageNames.length(); i++) + { + int pos = 0; + previous = pageNames.at(i-1).split('/').last(); + current = pageNames.at(i).split('/').last(); + for(; pos < current.length() && previous[pos] == current[pos]; pos++); + + if(pos < currentPrefixLenght && pos > 0) + { + frequency.insert(previous.left(currentPrefixLenght), currentPrefixCount); + currentPrefixLenght = pos; + currentPrefixCount++; + } + /* + else if(pos > currentPrefixLenght) + { + frequency.insert(pageNames.at(i-1).left(currentPrefixLenght), currentPrefixCount - 1); + currentPrefixLenght = pos; + currentPrefixCount = 2; + }*/ + else if(pos == 0) + { + frequency.insert(previous.left(currentPrefixLenght), currentPrefixCount); + currentPrefixLenght = current.length(); + currentPrefixCount = 1; + } + else + currentPrefixCount++; + } + + frequency.insert(previous.left(currentPrefixLenght), currentPrefixCount); + + uint maxFrequency = 0; + QString common_prefix = ""; + foreach(QString key, frequency.keys()) + { + if(maxFrequency < frequency.value(key)) + { + maxFrequency = frequency.value(key); + common_prefix = key; + } + } + + QRegExp allNumberRegExp("\\d+"); + if (allNumberRegExp.exactMatch(common_prefix)) + return ""; + + if(maxFrequency < pageNames.length() * 0.60) //the most common tipe of image file should a proper page, so we can asume that the common_prefix should be in, at least, the 60% of the pages + return ""; + + return common_prefix; +} + +void get_double_pages(const QList & pageNames, QList & singlePageNames/*out*/, QList & doublePageNames/*out*/) +{ + uint maxExpectedDoublePagesNumberLenght = (int)(log10(pageNames.length())+1) * 2; + + QString mostCommonPrefix = get_most_common_prefix(pageNames); + + foreach(const QString & pageName, pageNames) + { + if(is_double_page(pageName.split('/').last(), mostCommonPrefix, maxExpectedDoublePagesNumberLenght)) + doublePageNames.append(pageName); + else + singlePageNames.append(pageName); + } +} + +QList merge_pages(QList & singlePageNames, QList & doublePageNames) +{ + //NOTE: this implementation doesn't differ from std::merge using a custom comparator, but it can be easily tweaked if merging requeries an additional heuristic behaviour + QList pageNames; + + int i = 0; + int j = 0; + + while (i < singlePageNames.length() && j < doublePageNames.length()) + { + if (singlePageNames.at(i).compare(doublePageNames.at(j), Qt::CaseInsensitive) < 0) + pageNames.append(singlePageNames.at(i++)); + else + pageNames.append(doublePageNames.at(j++)); + } + + while (i < singlePageNames.length()) + pageNames.append(singlePageNames.at(i++)); + + while (j < doublePageNames.length()) + pageNames.append(doublePageNames.at(j++)); + + return pageNames; +} + + +void comic_pages_sort(QList & pageNames, YACReaderPageSortingMode sortingMode) +{ + switch(sortingMode) + { + case YACReaderNumericalSorting: + std::sort(pageNames.begin(), pageNames.end(), naturalSortLessThanCI); + break; + + case YACReaderHeuristicSorting: + { + std::sort(pageNames.begin(), pageNames.end(), naturalSortLessThanCI); + + QList singlePageNames; + QList doublePageNames; + + get_double_pages(pageNames, singlePageNames, doublePageNames); + + if(doublePageNames.length() > 0) + { + pageNames = merge_pages(singlePageNames, doublePageNames); + } + + break; + } + + case YACReaderAlphabeticalSorting: + std::sort(pageNames.begin(), pageNames.end()); + break; + } +} + diff --git a/common/gl/yacreader_flow_gl.cpp b/common/gl/yacreader_flow_gl.cpp index 6ab56239..58d10407 100644 --- a/common/gl/yacreader_flow_gl.cpp +++ b/common/gl/yacreader_flow_gl.cpp @@ -325,6 +325,7 @@ void YACReaderFlowGL::paintGL() glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if(numObjects>0) @@ -535,22 +536,22 @@ void YACReaderFlowGL::drawCover(const YACReader3DImage & image) //esquina inferior izquierda glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); glTexCoord2f(0.0f, 1.0f); - glVertex3f(w/2.f-0.2, -0.685f+h, 0.001f); + glVertex3f(w/2.f-0.2, -0.688f+h, 0.001f); //esquina inferior derecha glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); glTexCoord2f(1.0f, 1.0f); - glVertex3f(w/2.f-0.05, -0.685f+h, 0.001f); + glVertex3f(w/2.f-0.05, -0.688f+h, 0.001f); //esquina superior derecha glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); glTexCoord2f(1.0f, 0.0f); - glVertex3f(w/2.f-0.05, -0.485f+h, 0.001f); + glVertex3f(w/2.f-0.05, -0.488f+h, 0.001f); //esquina superior izquierda glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); glTexCoord2f(0.0f, 0.0f); - glVertex3f(w/2.f-0.2, -0.485f+h, 0.001f); + glVertex3f(w/2.f-0.2, -0.488f+h, 0.001f); glEnd(); glDisable(GL_TEXTURE_2D); diff --git a/common/gl_legacy/yacreader_flow_gl.cpp b/common/gl_legacy/yacreader_flow_gl.cpp index d367e20b..635927e1 100644 --- a/common/gl_legacy/yacreader_flow_gl.cpp +++ b/common/gl_legacy/yacreader_flow_gl.cpp @@ -309,8 +309,8 @@ void YACReaderFlowGL::initializeGL() void YACReaderFlowGL::paintGL() { - /*glClearDepth(1.0); - glClearColor(1,1,1,1);*/ + /*glClearDepth(1.0);*/ + glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /*glLoadIdentity(); glTranslatef(0.0, 0.0, -10.0); @@ -505,22 +505,22 @@ void YACReaderFlowGL::drawCover(const YACReader3DImage & image) //esquina inferior izquierda glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); glTexCoord2f(0.0f, 1.0f); - glVertex3f(w/2.f-0.2, -0.685f+h, 0.001f); + glVertex3f(w/2.f-0.2, -0.688f+h, 0.001f); //esquina inferior derecha - glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); + glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); glTexCoord2f(1.0f, 1.0f); - glVertex3f(w/2.f-0.05, -0.685f+h, 0.001f); + glVertex3f(w/2.f-0.05, -0.688f+h, 0.001f); //esquina superior derecha glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); glTexCoord2f(1.0f, 0.0f); - glVertex3f(w/2.f-0.05, -0.485f+h, 0.001f); + glVertex3f(w/2.f-0.05, -0.488f+h, 0.001f); //esquina superior izquierda glColor4f(RUP*opacity,RUP*opacity,RUP*opacity,1); glTexCoord2f(0.0f, 0.0f); - glVertex3f(w/2.f-0.2, -0.485f+h, 0.001f); + glVertex3f(w/2.f-0.2, -0.488f+h, 0.001f); glEnd(); glDisable(GL_TEXTURE_2D); diff --git a/common/qnaturalsorting.cpp b/common/qnaturalsorting.cpp index 97cbd5b0..873b06b4 100644 --- a/common/qnaturalsorting.cpp +++ b/common/qnaturalsorting.cpp @@ -1,245 +1,15 @@ -/* This file contains parts of the KDE libraries - Copyright (C) 1999 Ian Zepp (icszepp@islc.net) - Copyright (C) 2006 by Dominic Battre - Copyright (C) 2006 by Martin Pool - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - #include "qnaturalsorting.h" -//from KDE -/* -int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity) +#include + + + +int naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity caseSensitivity) { - // This method chops the input a and b into pieces of - // digits and non-digits (a1.05 becomes a | 1 | . | 05) - // and compares these pieces of a and b to each other - // (first with first, second with second, ...). - // - // This is based on the natural sort order code code by Martin Pool - // http://sourcefrog.net/projects/natsort/ - // Martin Pool agreed to license this under LGPL or GPL. - - // FIXME: Using toLower() to implement case insensitive comparison is - // sub-optimal, but is needed because we compare strings with - // localeAwareCompare(), which does not know about case sensitivity. - // A task has been filled for this in Qt Task Tracker with ID 205990. - // http://trolltech.com/developer/task-tracker/index_html?method=entry&id=205990 - QString a; - QString b; - if (caseSensitivity == Qt::CaseSensitive) { - a = _a; - b = _b; - } else { - a = _a.toLower(); - b = _b.toLower(); - } - - const QChar* currA = a.unicode(); // iterator over a - const QChar* currB = b.unicode(); // iterator over b - - if (currA == currB) { - return 0; - } - - const QChar* begSeqA = currA; // beginning of a new character sequence of a - const QChar* begSeqB = currB; - - while (!currA->isNull() && !currB->isNull()) { - if (currA->unicode() == QChar::ObjectReplacementCharacter) { - return 1; - } - - if (currB->unicode() == QChar::ObjectReplacementCharacter) { - return -1; - } - - if (currA->unicode() == QChar::ReplacementCharacter) { - return 1; - } - - if (currB->unicode() == QChar::ReplacementCharacter) { - return -1; - } - - // find sequence of characters ending at the first non-character - while (!currA->isNull() && !currA->isDigit() && !currA->isPunct() && !currA->isSpace()) { - ++currA; - } - - while (!currB->isNull() && !currB->isDigit() && !currB->isPunct() && !currB->isSpace()) { - ++currB; - } - - // compare these sequences - const QStringRef& subA(a.midRef(begSeqA - a.unicode(), currA - begSeqA)); - const QStringRef& subB(b.midRef(begSeqB - b.unicode(), currB - begSeqB)); - const int cmp = QStringRef::localeAwareCompare(subA, subB); - if (cmp != 0) { - return cmp < 0 ? -1 : +1; - } - - if (currA->isNull() || currB->isNull()) { - break; - } - - // find sequence of characters ending at the first non-character - while (currA->isPunct() || currA->isSpace() || currB->isPunct() || currB->isSpace()) { - if (*currA != *currB) { - return (*currA < *currB) ? -1 : +1; - } - ++currA; - ++currB; - } - - // now some digits follow... - if ((*currA == '0') || (*currB == '0')) { - // one digit-sequence starts with 0 -> assume we are in a fraction part - // do left aligned comparison (numbers are considered left aligned) - while (1) { - if (!currA->isDigit() && !currB->isDigit()) { - break; - } else if (!currA->isDigit()) { - return +1; - } else if (!currB->isDigit()) { - return -1; - } else if (*currA < *currB) { - return -1; - } else if (*currA > *currB) { - return + 1; - } - ++currA; - ++currB; - } - } else { - // No digit-sequence starts with 0 -> assume we are looking at some integer - // do right aligned comparison. - // - // The longest run of digits wins. That aside, the greatest - // value wins, but we can't know that it will until we've scanned - // both numbers to know that they have the same magnitude. - - bool isFirstRun = true; - int weight = 0; - while (1) { - if (!currA->isDigit() && !currB->isDigit()) { - if (weight != 0) { - return weight; - } - break; - } else if (!currA->isDigit()) { - if (isFirstRun) { - return *currA < *currB ? -1 : +1; - } else { - return -1; - } - } else if (!currB->isDigit()) { - if (isFirstRun) { - return *currA < *currB ? -1 : +1; - } else { - return +1; - } - } else if ((*currA < *currB) && (weight == 0)) { - weight = -1; - } else if ((*currA > *currB) && (weight == 0)) { - weight = + 1; - } - ++currA; - ++currB; - isFirstRun = false; - } - } - - begSeqA = currA; - begSeqB = currB; - } - - if (currA->isNull() && currB->isNull()) { - return 0; - } - - return currA->isNull() ? -1 : + 1; -} - -*/ -static inline QChar getNextChar(const QString &s, int location) -{ - return (location < s.length()) ? s.at(location) : QChar(); -} - -int naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs) -{ - for (int l1 = 0, l2 = 0; l1 <= s1.count() && l2 <= s2.count(); ++l1, ++l2) { - // skip spaces, tabs and 0's - QChar c1 = getNextChar(s1, l1); - while (c1.isSpace()) - c1 = getNextChar(s1, ++l1); - QChar c2 = getNextChar(s2, l2); - while (c2.isSpace()) - c2 = getNextChar(s2, ++l2); - - if (c1.isDigit() && c2.isDigit()) { - while (c1.digitValue() == 0) - c1 = getNextChar(s1, ++l1); - while (c2.digitValue() == 0) - c2 = getNextChar(s2, ++l2); - - int lookAheadLocation1 = l1; - int lookAheadLocation2 = l2; - int currentReturnValue = 0; - // find the last digit, setting currentReturnValue as we go if it isn't equal - for ( - QChar lookAhead1 = c1, lookAhead2 = c2; - (lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length()); - lookAhead1 = getNextChar(s1, ++lookAheadLocation1), - lookAhead2 = getNextChar(s2, ++lookAheadLocation2) - ) { - bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit(); - bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit(); - if (!is1ADigit && !is2ADigit) - break; - if (!is1ADigit) - return -1; - if (!is2ADigit) - return 1; - if (currentReturnValue == 0) { - if (lookAhead1 < lookAhead2) { - currentReturnValue = -1; - } else if (lookAhead1 > lookAhead2) { - currentReturnValue = 1; - } - } - } - if (currentReturnValue != 0) - return currentReturnValue; - } - - if (cs == Qt::CaseInsensitive) { - if (!c1.isLower()) c1 = c1.toLower(); - if (!c2.isLower()) c2 = c2.toLower(); - } - int r = QString::localeAwareCompare(c1, c2); - if (r < 0) - return -1; - if (r > 0) - return 1; - } - // The two strings are the same (02 == 2) so fall back to the normal sort - return QString::compare(s1, s2, cs); + QCollator c; + c.setCaseSensitivity(caseSensitivity); + c.setNumericMode(true); + return c.compare(s1, s2); } bool naturalSortLessThanCS( const QString &left, const QString &right ) { diff --git a/common/yacreader_global.h b/common/yacreader_global.h index 57afde3f..9d65259c 100644 --- a/common/yacreader_global.h +++ b/common/yacreader_global.h @@ -9,6 +9,10 @@ #define VERSION "8.0.0" +#define USE_BACKGROUND_IMAGE_IN_GRID_VIEW "USE_BACKGROUND_IMAGE_IN_GRID_VIEW" +#define OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW "OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW" +#define BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW "BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW" + #define NUM_DAYS_BETWEEN_VERSION_CHECKS "NUM_DAYS_BETWEEN_VERSION_CHECKS" #define LAST_VERSION_CHECK "LAST_VERSION_CHECK" diff --git a/images/readRibbon.png b/images/readRibbon.png index 43bbdf7a..4dcd32e2 100644 Binary files a/images/readRibbon.png and b/images/readRibbon.png differ diff --git a/images/readingRibbon.png b/images/readingRibbon.png index 816f2d81..476912ef 100644 Binary files a/images/readingRibbon.png and b/images/readingRibbon.png differ