parent
758fd6c687
commit
fa2779e6b9
14 changed files with 407 additions and 496 deletions
@ -1,218 +0,0 @@ |
||||
/* ============================================================
|
||||
* AutoScroll - Autoscroll for QupZilla |
||||
* Copyright (C) 2014 David Rosca <nowrep@gmail.com> |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program 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 General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */ |
||||
#include "autoscroller.h" |
||||
#include "framescroller.h" |
||||
#include "webview.h" |
||||
#include "webpage.h" |
||||
|
||||
#include <QApplication> |
||||
#include <QMouseEvent> |
||||
#include <QWebFrame> |
||||
#include <QSettings> |
||||
#include <QLabel> |
||||
|
||||
AutoScroller::AutoScroller(const QString &settingsFile, QObject* parent) |
||||
: QObject(parent) |
||||
, m_view(0) |
||||
, m_settingsFile(settingsFile) |
||||
{ |
||||
m_indicator = new QLabel; |
||||
m_indicator->resize(32, 32); |
||||
m_indicator->setContentsMargins(0, 0, 0, 0); |
||||
m_indicator->installEventFilter(this); |
||||
|
||||
QSettings settings(m_settingsFile, QSettings::IniFormat); |
||||
settings.beginGroup("AutoScroll"); |
||||
|
||||
m_frameScroller = new FrameScroller(this); |
||||
m_frameScroller->setScrollDivider(settings.value("ScrollDivider", 8.0).toDouble()); |
||||
|
||||
settings.endGroup(); |
||||
} |
||||
|
||||
AutoScroller::~AutoScroller() |
||||
{ |
||||
delete m_indicator; |
||||
} |
||||
|
||||
bool AutoScroller::mouseMove(QObject* obj, QMouseEvent* event) |
||||
{ |
||||
Q_UNUSED(obj) |
||||
|
||||
if (m_indicator->isVisible()) { |
||||
QRect rect = indicatorGlobalRect(); |
||||
int xlength = 0; |
||||
int ylength = 0; |
||||
|
||||
if (rect.left() > event->globalPos().x()) { |
||||
xlength = event->globalPos().x() - rect.left(); |
||||
} |
||||
else if (rect.right() < event->globalPos().x()) { |
||||
xlength = event->globalPos().x() - rect.right(); |
||||
} |
||||
if (rect.top() > event->globalPos().y()) { |
||||
ylength = event->globalPos().y() - rect.top(); |
||||
} |
||||
else if (rect.bottom() < event->globalPos().y()) { |
||||
ylength = event->globalPos().y() - rect.bottom(); |
||||
} |
||||
|
||||
m_frameScroller->startScrolling(xlength, ylength); |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool AutoScroller::mousePress(QObject* obj, QMouseEvent* event) |
||||
{ |
||||
bool middleButton = event->buttons() == Qt::MiddleButton; |
||||
WebView* view = qobject_cast<WebView*>(obj); |
||||
Q_ASSERT(view); |
||||
|
||||
// Start?
|
||||
if (m_view != view && middleButton) { |
||||
return showIndicator(view, event->pos()); |
||||
} |
||||
else if (!m_indicator->isVisible() && middleButton) { |
||||
return showIndicator(view, event->pos()); |
||||
} |
||||
|
||||
// Stop
|
||||
if (m_indicator->isVisible()) { |
||||
stopScrolling(); |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool AutoScroller::mouseRelease(QObject* obj, QMouseEvent* event) |
||||
{ |
||||
Q_UNUSED(obj) |
||||
|
||||
if (m_indicator->isVisible()) { |
||||
if (!indicatorGlobalRect().contains(event->globalPos())) { |
||||
stopScrolling(); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
double AutoScroller::scrollDivider() const |
||||
{ |
||||
return m_frameScroller->scrollDivider(); |
||||
} |
||||
|
||||
void AutoScroller::setScrollDivider(double divider) |
||||
{ |
||||
QSettings settings(m_settingsFile, QSettings::IniFormat); |
||||
settings.beginGroup("AutoScroll"); |
||||
settings.setValue("ScrollDivider", divider); |
||||
settings.endGroup(); |
||||
|
||||
m_frameScroller->setScrollDivider(divider); |
||||
} |
||||
|
||||
bool AutoScroller::eventFilter(QObject* obj, QEvent* event) |
||||
{ |
||||
if (obj == m_indicator) { |
||||
switch (event->type()) { |
||||
case QEvent::Enter: |
||||
m_frameScroller->stopScrolling(); |
||||
break; |
||||
|
||||
case QEvent::Wheel: |
||||
case QEvent::Hide: |
||||
case QEvent::MouseButtonPress: |
||||
stopScrolling(); |
||||
break; |
||||
|
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool AutoScroller::showIndicator(WebView* view, const QPoint &pos) |
||||
{ |
||||
QWebFrame* frame = view->page()->frameAt(pos); |
||||
|
||||
if (!frame) { |
||||
return false; |
||||
} |
||||
|
||||
const QWebHitTestResult res = frame->hitTestContent(pos); |
||||
|
||||
if (res.isContentEditable() || !res.linkUrl().isEmpty()) { |
||||
return false; |
||||
} |
||||
|
||||
bool vertical = frame->scrollBarGeometry(Qt::Vertical).isValid(); |
||||
bool horizontal = frame->scrollBarGeometry(Qt::Horizontal).isValid(); |
||||
|
||||
if (!vertical && !horizontal) { |
||||
return false; |
||||
} |
||||
|
||||
if (vertical && horizontal) { |
||||
m_indicator->setPixmap(QPixmap(":/autoscroll/data/scroll_all.png")); |
||||
} |
||||
else if (vertical) { |
||||
m_indicator->setPixmap(QPixmap(":/autoscroll/data/scroll_vertical.png")); |
||||
} |
||||
else { |
||||
m_indicator->setPixmap(QPixmap(":/autoscroll/data/scroll_horizontal.png")); |
||||
} |
||||
|
||||
m_view = view; |
||||
|
||||
QPoint p; |
||||
p.setX(pos.x() - m_indicator->pixmap()->width() / 2); |
||||
p.setY(pos.y() - m_indicator->pixmap()->height() / 2); |
||||
|
||||
m_indicator->setParent(view->overlayWidget()); |
||||
m_indicator->move(p); |
||||
m_indicator->show(); |
||||
|
||||
m_frameScroller->setFrame(frame); |
||||
|
||||
m_view->grabMouse(); |
||||
QApplication::setOverrideCursor(Qt::ArrowCursor); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void AutoScroller::stopScrolling() |
||||
{ |
||||
m_view->releaseMouse(); |
||||
QApplication::restoreOverrideCursor(); |
||||
|
||||
m_indicator->hide(); |
||||
m_indicator->setParent(0); |
||||
m_frameScroller->stopScrolling(); |
||||
} |
||||
|
||||
QRect AutoScroller::indicatorGlobalRect() const |
||||
{ |
||||
QPoint pos = m_indicator->parentWidget()->mapToGlobal(m_indicator->geometry().topLeft()); |
||||
return QRect(pos.x(), pos.y(), m_indicator->width(), m_indicator->height()); |
||||
} |
||||
@ -1,59 +0,0 @@ |
||||
/* ============================================================
|
||||
* AutoScroll - Autoscroll for QupZilla |
||||
* Copyright (C) 2014 David Rosca <nowrep@gmail.com> |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program 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 General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */ |
||||
#ifndef AUTOSCROLLER_H |
||||
#define AUTOSCROLLER_H |
||||
|
||||
#include <QObject> |
||||
#include <QPoint> |
||||
|
||||
class QMouseEvent; |
||||
class QLabel; |
||||
class QRect; |
||||
|
||||
class WebView; |
||||
class FrameScroller; |
||||
|
||||
class AutoScroller : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
public: |
||||
explicit AutoScroller(const QString &settingsFile, QObject* parent = 0); |
||||
~AutoScroller(); |
||||
|
||||
bool mouseMove(QObject* obj, QMouseEvent* event); |
||||
bool mousePress(QObject* obj, QMouseEvent* event); |
||||
bool mouseRelease(QObject* obj, QMouseEvent* event); |
||||
|
||||
double scrollDivider() const; |
||||
void setScrollDivider(double divider); |
||||
|
||||
private: |
||||
bool eventFilter(QObject* obj, QEvent* event); |
||||
|
||||
bool showIndicator(WebView* view, const QPoint &pos); |
||||
void stopScrolling(); |
||||
|
||||
QRect indicatorGlobalRect() const; |
||||
|
||||
WebView* m_view; |
||||
QLabel* m_indicator; |
||||
FrameScroller* m_frameScroller; |
||||
QString m_settingsFile; |
||||
}; |
||||
|
||||
#endif // AUTOSCROLLER_H
|
||||
@ -0,0 +1,301 @@ |
||||
/* |
||||
* AutoScroll |
||||
* |
||||
* modified from https://chrome.google.com/webstore/detail/autoscroll/occjjkgifpmdgodlplnacmkejpdionan
|
||||
*/ |
||||
|
||||
(function () { |
||||
"use strict"; |
||||
|
||||
function hypot(x, y) { |
||||
return Math.sqrt(x * x + y * y) |
||||
} |
||||
|
||||
var startAnimation = function (f) { |
||||
(function anon() { |
||||
f(requestAnimationFrame(anon)) |
||||
})() |
||||
} |
||||
var stopAnimation = cancelAnimationFrame |
||||
|
||||
// The timer that does the actual scrolling; must be very fast so the scrolling is smooth
|
||||
var cycle = { |
||||
dirX: 0, |
||||
dirY: 0, |
||||
start: function (elem) { |
||||
var self = this |
||||
|
||||
startAnimation(function (id) { |
||||
self.timeout = id |
||||
|
||||
var x = self.dirX |
||||
, y = self.dirY |
||||
|
||||
if (x !== 0) { |
||||
elem.scrollLeft += x |
||||
} |
||||
if (y !== 0) { |
||||
elem.scrollTop += y |
||||
} |
||||
}) |
||||
}, |
||||
stop: function () { |
||||
this.dirX = 0 |
||||
this.dirY = 0 |
||||
stopAnimation(this.timeout) |
||||
} |
||||
} |
||||
|
||||
var options = { |
||||
dragThreshold: 10, |
||||
moveThreshold: 20, |
||||
moveSpeed: %MOVE_SPEED%, |
||||
stickyScroll: true, |
||||
ctrlClick: %CTRL_CLICK%, |
||||
middleClick: %MIDDLE_CLICK% |
||||
} |
||||
|
||||
function make(parent, f) { |
||||
var state = {} |
||||
|
||||
function image(o) { |
||||
if (o.width && o.height) { |
||||
return "data:image/png;base64,%IMG_ALL%" |
||||
} else if (o.width) { |
||||
return "data:image/png;base64,%IMG_HORIZONTAL%" |
||||
} else { |
||||
return "data:image/png;base64,%IMG_VERTICAL%" |
||||
} |
||||
} |
||||
|
||||
function shouldSticky(x, y) { |
||||
return options["stickyScroll"] && hypot(x, y) < options["dragThreshold"] |
||||
} |
||||
|
||||
function scale(value) { |
||||
return value / options["moveSpeed"] |
||||
} |
||||
|
||||
var e = document.createElement("iframe") |
||||
e.style.setProperty("display", "none", "important") |
||||
e.style.setProperty("position", "fixed", "important") |
||||
e.style.setProperty("padding", "0px", "important") |
||||
e.style.setProperty("margin", "0px", "important") |
||||
e.style.setProperty("left", "0px", "important") |
||||
e.style.setProperty("top", "0px", "important") |
||||
e.style.setProperty("width", "100%", "important") |
||||
e.style.setProperty("height", "100%", "important") |
||||
e.style.setProperty("background-color", "transparent", "important") |
||||
e.style.setProperty("z-index", "2147483647", "important") // 32-bit signed int
|
||||
e.style.setProperty("border", "none", "important") |
||||
parent.appendChild(e) |
||||
|
||||
var inner = e.contentDocument.body |
||||
|
||||
function stopScroll(e) { |
||||
if (e.stopImmediatePropagation) { |
||||
e.stopImmediatePropagation() |
||||
} |
||||
e.stopPropagation() |
||||
} |
||||
|
||||
function unclick() { |
||||
cycle.stop() |
||||
inner.style.removeProperty("cursor") |
||||
inner.style.setProperty("display", "none", "important") |
||||
e.style.setProperty("display", "none", "important") |
||||
delete state.oldX |
||||
delete state.oldY |
||||
delete state.click |
||||
|
||||
// Force relayout
|
||||
getComputedStyle(inner).left; |
||||
getComputedStyle(e).left; |
||||
getComputedStyle(eCursor).left; |
||||
|
||||
removeEventListener("scroll", stopScroll, true) |
||||
} |
||||
|
||||
inner.addEventListener("mousewheel", function (event) { |
||||
event.preventDefault() |
||||
}, true) |
||||
|
||||
inner.addEventListener("mousemove", function (event) { |
||||
var x = event.clientX - state.oldX, |
||||
y = event.clientY - state.oldY |
||||
|
||||
if (hypot(x, y) > options["moveThreshold"]) { |
||||
x = scale(x) |
||||
y = scale(y) |
||||
|
||||
cycle.dirX = Math.round(x) | 0 |
||||
cycle.dirY = Math.round(y) | 0 |
||||
} else { |
||||
cycle.dirX = 0 |
||||
cycle.dirY = 0 |
||||
} |
||||
}, true) |
||||
|
||||
inner.addEventListener("mouseup", function (event) { |
||||
var x = event.clientX - state.oldX, |
||||
y = event.clientY - state.oldY |
||||
|
||||
if (state.click || !shouldSticky(x, y)) { |
||||
unclick() |
||||
} else { |
||||
state.click = true |
||||
} |
||||
}, true) |
||||
|
||||
var eCursor = document.createElement("img") |
||||
eCursor.style.setProperty("position", "absolute") |
||||
inner.appendChild(eCursor) |
||||
|
||||
function show(o, x, y) { |
||||
state.oldX = x |
||||
state.oldY = y |
||||
|
||||
addEventListener("scroll", stopScroll, true) |
||||
|
||||
eCursor.setAttribute("src", image(o)) |
||||
eCursor.style.setProperty("left", (x - 13) + "px") |
||||
eCursor.style.setProperty("top", (y - 13) + "px") |
||||
inner.style.setProperty("display", "block", "important") |
||||
e.style.setProperty("display", "block", "important") |
||||
cycle.start(o.element) |
||||
} |
||||
|
||||
f(show) |
||||
} |
||||
|
||||
var htmlNode = document.documentElement |
||||
|
||||
function isInvalid(elem) { |
||||
if (elem.localName === "input") { |
||||
return !(elem.type === "button" || |
||||
elem.type === "checkbox" || |
||||
elem.type === "file" || |
||||
elem.type === "hidden" || |
||||
elem.type === "image" || |
||||
elem.type === "radio" || |
||||
elem.type === "reset" || |
||||
elem.type === "submit") |
||||
} else { |
||||
while (true) { |
||||
if (elem === document.body || elem === htmlNode) { |
||||
return false |
||||
} else if (elem.localName === "a" && elem.href || elem.localName === "textarea") { |
||||
return true |
||||
} else { |
||||
elem = elem.parentNode |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
function canScroll(elem, style) { |
||||
return style === "auto" || style === "scroll" |
||||
} |
||||
|
||||
function canScrollTop(elem, style) { |
||||
return style === "auto" || style === "scroll" || style === "visible" |
||||
} |
||||
|
||||
function hasWidth(elem, can) { |
||||
var style = getComputedStyle(elem) |
||||
return can(elem, style.overflowX) && elem.scrollWidth > elem.clientWidth |
||||
} |
||||
|
||||
function hasHeight(elem, can) { |
||||
var style = getComputedStyle(elem) |
||||
return can(elem, style.overflowY) && elem.scrollHeight > elem.clientHeight |
||||
} |
||||
|
||||
function findScroll(elem) { |
||||
while (elem !== document && |
||||
elem !== document.body && |
||||
elem !== htmlNode) { |
||||
|
||||
var width = hasWidth(elem, canScroll) |
||||
, height = hasHeight(elem, canScroll) |
||||
|
||||
if (width || height) { |
||||
return { |
||||
element: elem, |
||||
width: width, |
||||
height: height |
||||
} |
||||
|
||||
} else { |
||||
elem = elem.parentNode |
||||
} |
||||
} |
||||
|
||||
var body_width = hasWidth(document.body, canScrollTop); |
||||
var body_height = hasHeight(document.body, canScrollTop); |
||||
|
||||
var html_width = hasWidth(htmlNode, canScrollTop); |
||||
var html_height = hasHeight(htmlNode, canScrollTop); |
||||
|
||||
var width = (body_width || html_width); |
||||
var height = (body_height || html_height); |
||||
|
||||
if (width || height) { |
||||
return { |
||||
element: document.body, |
||||
width: width, |
||||
height: height |
||||
}; |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
function getBody(x) { |
||||
if (x === null) { |
||||
return null; |
||||
|
||||
} else { |
||||
return { |
||||
element: (x.element === htmlNode ? document.body : x.element), |
||||
width: x.width, |
||||
height: x.height |
||||
} |
||||
} |
||||
} |
||||
|
||||
function ready(f) { |
||||
if (document.body) { |
||||
f() |
||||
} else { |
||||
var observer = new MutationObserver(function () { |
||||
if (document.body) { |
||||
observer.disconnect() |
||||
f() |
||||
} |
||||
}) |
||||
observer.observe(htmlNode, { childList: true }) |
||||
} |
||||
} |
||||
|
||||
ready(function () { |
||||
make(document.body, function (show) { |
||||
addEventListener("mousedown", function (e) { |
||||
if (((e.button === 1 && options.middleClick) || |
||||
(e.button === 0 && (e.ctrlKey || e.metaKey) && options.ctrlClick)) && |
||||
e.clientX < htmlNode.clientWidth && |
||||
!isInvalid(e.target)) { |
||||
var elem = getBody(findScroll(e.target)) |
||||
if (elem !== null) { |
||||
if (e.stopImmediatePropagation) { |
||||
e.stopImmediatePropagation() |
||||
} |
||||
e.stopPropagation() |
||||
e.preventDefault() |
||||
show(elem, e.clientX, e.clientY) |
||||
} |
||||
} |
||||
}, true) |
||||
}) |
||||
}) |
||||
})() |
||||
@ -1,74 +0,0 @@ |
||||
/* ============================================================
|
||||
* AutoScroll - Autoscroll for QupZilla |
||||
* Copyright (C) 2014 David Rosca <nowrep@gmail.com> |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program 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 General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */ |
||||
#include "framescroller.h" |
||||
|
||||
#include <QTimer> |
||||
#include <QWebFrame> |
||||
#include <QtCore/qmath.h> |
||||
|
||||
FrameScroller::FrameScroller(QObject* parent) |
||||
: QObject(parent) |
||||
, m_frame(0) |
||||
, m_lengthX(0) |
||||
, m_lengthY(0) |
||||
, m_divider(8.0) |
||||
{ |
||||
m_timer = new QTimer(this); |
||||
m_timer->setInterval(10); |
||||
connect(m_timer, SIGNAL(timeout()), this, SLOT(scrollStep())); |
||||
} |
||||
|
||||
void FrameScroller::setFrame(QWebFrame* frame) |
||||
{ |
||||
m_frame = frame; |
||||
} |
||||
|
||||
double FrameScroller::scrollDivider() const |
||||
{ |
||||
return m_divider; |
||||
} |
||||
|
||||
void FrameScroller::setScrollDivider(double divider) |
||||
{ |
||||
m_divider = divider; |
||||
} |
||||
|
||||
void FrameScroller::startScrolling(int lengthX, int lengthY) |
||||
{ |
||||
Q_ASSERT(m_frame); |
||||
|
||||
m_lengthX = lengthX; |
||||
m_lengthY = lengthY; |
||||
|
||||
if (m_lengthX == 0 && m_lengthY == 0) { |
||||
m_timer->stop(); |
||||
} |
||||
else if (!m_timer->isActive()) { |
||||
m_timer->start(); |
||||
} |
||||
} |
||||
|
||||
void FrameScroller::stopScrolling() |
||||
{ |
||||
m_timer->stop(); |
||||
} |
||||
|
||||
void FrameScroller::scrollStep() |
||||
{ |
||||
m_frame->scroll(qCeil(m_lengthX / m_divider), qCeil(m_lengthY / m_divider)); |
||||
} |
||||
@ -1,53 +0,0 @@ |
||||
/* ============================================================
|
||||
* AutoScroll - Autoscroll for QupZilla |
||||
* Copyright (C) 2014 David Rosca <nowrep@gmail.com> |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation, either version 3 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program 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 General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* ============================================================ */ |
||||
#ifndef FRAMESCROLLER_H |
||||
#define FRAMESCROLLER_H |
||||
|
||||
#include <QObject> |
||||
|
||||
class QTimer; |
||||
class QWebFrame; |
||||
|
||||
class FrameScroller : public QObject |
||||
{ |
||||
Q_OBJECT |
||||
|
||||
public: |
||||
explicit FrameScroller(QObject* parent = 0); |
||||
|
||||
void setFrame(QWebFrame* frame); |
||||
|
||||
double scrollDivider() const; |
||||
void setScrollDivider(double divider); |
||||
|
||||
void startScrolling(int lengthX, int lengthY); |
||||
void stopScrolling(); |
||||
|
||||
private slots: |
||||
void scrollStep(); |
||||
|
||||
private: |
||||
QWebFrame* m_frame; |
||||
QTimer* m_timer; |
||||
|
||||
int m_lengthX; |
||||
int m_lengthY; |
||||
double m_divider; |
||||
}; |
||||
|
||||
#endif // FRAMESCROLLER_H
|
||||
Loading…
Reference in new issue