mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-24 19:02:51 +00:00
664 lines
18 KiB
C++
664 lines
18 KiB
C++
/*
|
|
* Copyright (C) 2003 by Unai Garro <ugarro@users.sourceforge.net>
|
|
* Copyright (C) 2004 by Enrico Ros <rosenric@dei.unipd.it>
|
|
* Copyright (C) 2004 by Stephan Kulow <coolo@kde.org>
|
|
* Copyright (C) 2004 by Oswald Buddenhagen <ossi@kde.org>
|
|
*
|
|
* 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 2 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/*
|
|
* Generic Kdm Item
|
|
*/
|
|
|
|
#include "kdmitem.h"
|
|
#include "kdmlayout.h"
|
|
#include "kdmthemer.h"
|
|
|
|
#include <kdm_greet.h> // debug*
|
|
|
|
#include <QEvent>
|
|
#include <QLineEdit>
|
|
#include <QPainter>
|
|
|
|
static bool
|
|
toBool(const QString &str)
|
|
{
|
|
bool ok;
|
|
int val = str.toInt(&ok);
|
|
if (!ok)
|
|
return str == "true";
|
|
return val != 0;
|
|
}
|
|
|
|
KdmItem::KdmItem(QObject *parent, const QDomNode &node)
|
|
: QObject(parent)
|
|
, boxManager(0)
|
|
, fixedManager(0)
|
|
, myWidget(0)
|
|
, m_showTypeInvert(false)
|
|
, m_minScrWidth(0)
|
|
, m_minScrHeight(0)
|
|
, m_visible(true)
|
|
, m_shown(true)
|
|
{
|
|
QDomNode showNode = node.namedItem("show");
|
|
if (!showNode.isNull()) {
|
|
QDomElement sel = showNode.toElement();
|
|
|
|
QString modes = sel.attribute("modes");
|
|
if (!modes.isNull() &&
|
|
(modes == "nowhere" ||
|
|
(modes != "everywhere" &&
|
|
!modes.split(",", QString::SkipEmptyParts).contains("console"))))
|
|
{
|
|
m_visible = false;
|
|
return;
|
|
}
|
|
|
|
m_showType = sel.attribute("type");
|
|
if (!m_showType.isNull()) {
|
|
if (m_showType[0] == '!') {
|
|
m_showType.remove(0, 1);
|
|
m_showTypeInvert = true;
|
|
}
|
|
if (!m_showType.startsWith("plugin-") &&
|
|
themer()->typeVisible(m_showType) == m_showTypeInvert)
|
|
{
|
|
m_visible = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_minScrWidth = sel.attribute("min-screen-width").toInt();
|
|
m_minScrHeight = sel.attribute("min-screen-height").toInt();
|
|
}
|
|
|
|
// Set default layout for every item
|
|
currentManager = MNone;
|
|
geom.pos.x.type = geom.pos.y.type =
|
|
geom.size.x.type = geom.size.y.type = DTnone;
|
|
geom.minSize.x.type = geom.minSize.y.type =
|
|
geom.maxSize.x.type = geom.maxSize.y.type = DTpixel;
|
|
geom.minSize.x.val = geom.minSize.y.val = 0;
|
|
geom.maxSize.x.val = geom.maxSize.y.val = 1000000;
|
|
geom.anchor = "nw";
|
|
geom.expand = 0;
|
|
|
|
// Set defaults for derived item's properties
|
|
state = Snormal;
|
|
|
|
KdmItem *parentItem = qobject_cast<KdmItem *>(parent);
|
|
if (!parentItem)
|
|
style.frame = false, style.guistyle = 0;
|
|
else
|
|
style = parentItem->style;
|
|
|
|
// Read the mandatory Pos tag. Other tags such as normal, prelighted,
|
|
// etc.. are read under specific implementations.
|
|
QDomNodeList childList = node.childNodes();
|
|
for (int nod = 0; nod < childList.count(); nod++) {
|
|
QDomNode child = childList.item(nod);
|
|
QDomElement el = child.toElement();
|
|
QString tagName = el.tagName();
|
|
|
|
if (tagName == "pos") {
|
|
parseSize(el.attribute("x", QString()), geom.pos.x);
|
|
parseSize(el.attribute("y", QString()), geom.pos.y);
|
|
parseSize(el.attribute("width", QString()), geom.size.x);
|
|
parseSize(el.attribute("height", QString()), geom.size.y);
|
|
parseSize(el.attribute("min-width", QString()), geom.minSize.x);
|
|
parseSize(el.attribute("min-height", QString()), geom.minSize.y);
|
|
parseSize(el.attribute("max-width", QString()), geom.maxSize.x);
|
|
parseSize(el.attribute("max-height", QString()), geom.maxSize.y);
|
|
geom.anchor = el.attribute("anchor", "nw");
|
|
geom.expand = toBool(el.attribute("expand", "false"));
|
|
} else if (tagName == "buddy") {
|
|
buddy = el.attribute("idref", "");
|
|
} else if (tagName == "style") {
|
|
parseStyle(el, style);
|
|
}
|
|
}
|
|
|
|
if (!style.font.present)
|
|
parseFont("Sans 14", style.font);
|
|
|
|
QDomElement el = node.toElement();
|
|
setObjectName(el.attribute("id", QString::number((ulong)this, 16)));
|
|
isButton = toBool(el.attribute("button", "false"));
|
|
isBackground = toBool(el.attribute("background", "false"));
|
|
QString screen = el.attribute("screen", isBackground ? "all" : "greeter");
|
|
paintOnScreen =
|
|
screen == "greeter" ? ScrGreeter :
|
|
screen == "other" ? ScrOther : ScrAll;
|
|
|
|
if (!parentItem)
|
|
// The "toplevel" node (the screen) is really just like a fixed node
|
|
setFixedLayout();
|
|
else
|
|
// Tell 'parent' to add 'me' to its children
|
|
parentItem->addChildItem(this);
|
|
}
|
|
|
|
KdmItem::~KdmItem()
|
|
{
|
|
delete boxManager;
|
|
delete fixedManager;
|
|
}
|
|
|
|
void
|
|
KdmItem::update()
|
|
{
|
|
forEachChild (itm)
|
|
itm->update();
|
|
}
|
|
|
|
void
|
|
KdmItem::needUpdate()
|
|
{
|
|
emit needUpdate(area.x(), area.y(), area.width(), area.height());
|
|
}
|
|
|
|
void
|
|
KdmItem::updateThisVisible()
|
|
{
|
|
bool show = m_shown;
|
|
if (show && (!m_showType.isNull() || m_minScrWidth || m_minScrHeight)) {
|
|
KdmThemer *thm = themer();
|
|
if ((!m_showType.isNull() &&
|
|
!(thm->typeVisible(m_showType) ^ m_showTypeInvert)) ||
|
|
(thm->widget() &&
|
|
(thm->widget()->width() < m_minScrWidth ||
|
|
thm->widget()->height() < m_minScrHeight)))
|
|
{
|
|
show = false;
|
|
}
|
|
}
|
|
if (m_visible != show) {
|
|
m_visible = show;
|
|
emit needPlacement();
|
|
}
|
|
}
|
|
|
|
void
|
|
KdmItem::setVisible(bool show)
|
|
{
|
|
m_shown = show;
|
|
updateThisVisible();
|
|
}
|
|
|
|
void
|
|
KdmItem::updateVisible()
|
|
{
|
|
updateThisVisible();
|
|
forEachChild (itm)
|
|
itm->updateVisible();
|
|
}
|
|
|
|
KdmThemer *
|
|
KdmItem::themer()
|
|
{
|
|
if (KdmThemer *thm = qobject_cast<KdmThemer *>(parent()))
|
|
return thm;
|
|
if (KdmItem *parentItem = qobject_cast<KdmItem *>(parent()))
|
|
return parentItem->themer();
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
KdmItem::setWidget(QWidget *widget)
|
|
{
|
|
if ((myWidget = widget)) {
|
|
myWidget->hide(); // yes, really
|
|
connect(myWidget, SIGNAL(destroyed()), SLOT(widgetGone()));
|
|
setWidgetAttribs(myWidget);
|
|
}
|
|
|
|
emit needPlugging();
|
|
emit needPlacement();
|
|
}
|
|
|
|
void
|
|
KdmItem::widgetGone()
|
|
{
|
|
myWidget = 0;
|
|
|
|
emit needPlugging();
|
|
emit needPlacement();
|
|
}
|
|
|
|
void
|
|
KdmItem::setWidgetAttribs(QWidget *widget)
|
|
{
|
|
widget->setStyle(style.guistyle);
|
|
widget->setPalette(style.palette);
|
|
::setWidgetAttribs(widget, style, style.frame);
|
|
widget->installEventFilter(this);
|
|
updatePalette(widget);
|
|
}
|
|
|
|
void
|
|
KdmItem::updatePalette(QWidget *w)
|
|
{
|
|
// line edits set Base as the background role. however, they actively paint
|
|
// the background of the "text area" themselves anyway, and setting this
|
|
// property would also fill the surrounding window aera, which is ugly.
|
|
bool set = !qobject_cast<QLineEdit *>(w) &&
|
|
w->palette().isBrushSet(w->palette().currentColorGroup(),
|
|
w->backgroundRole());
|
|
w->setAutoFillBackground(set);
|
|
}
|
|
|
|
bool
|
|
KdmItem::eventFilter(QObject *o, QEvent *e)
|
|
{
|
|
if (e->type() == QEvent::WindowActivate ||
|
|
e->type() == QEvent::WindowDeactivate ||
|
|
e->type() == QEvent::EnabledChange)
|
|
{
|
|
updatePalette((QWidget *)o);
|
|
} else if (e->type() == QEvent::ChildAdded) {
|
|
::setWidgetAttribs(myWidget, style, style.frame);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
KdmItem::showWidget(bool show)
|
|
{
|
|
if (!isVisible())
|
|
show = false;
|
|
if (myWidget) {
|
|
if (show) {
|
|
QSize sz(area.size().expandedTo(myWidget->minimumSize())
|
|
.boundedTo(myWidget->maximumSize()));
|
|
QSize off((area.size() - sz) / 2);
|
|
myWidget->setGeometry(
|
|
area.x() + off.width(), area.y() + off.height(),
|
|
sz.width(), sz.height());
|
|
}
|
|
myWidget->setVisible(show);
|
|
}
|
|
forEachChild (itm)
|
|
itm->showWidget(show);
|
|
}
|
|
|
|
void
|
|
KdmItem::plugActions(bool plug)
|
|
{
|
|
if (myWidget)
|
|
plug = false;
|
|
doPlugActions(plug);
|
|
forEachChild (itm)
|
|
itm->plugActions(plug);
|
|
}
|
|
|
|
void
|
|
KdmItem::doPlugActions(bool)
|
|
{
|
|
}
|
|
|
|
/* This is called as a result of KdmLayout::update, and directly on the root */
|
|
void
|
|
KdmItem::setGeometry(QStack<QSize> &parentSizes, const QRect &newGeometry, bool force)
|
|
{
|
|
enter("Item::setGeometry") << objectName() << newGeometry;
|
|
// check if already 'in place'
|
|
if (!force && area == newGeometry) {
|
|
leave() << "unchanged";
|
|
return;
|
|
}
|
|
|
|
area = newGeometry;
|
|
|
|
// recurr to all boxed children
|
|
if (boxManager && !boxManager->isEmpty())
|
|
boxManager->update(parentSizes, newGeometry, force);
|
|
|
|
// recurr to all fixed children
|
|
if (fixedManager && !fixedManager->isEmpty())
|
|
fixedManager->update(parentSizes, newGeometry, force);
|
|
|
|
// TODO send *selective* repaint signal
|
|
|
|
leave() << "done";
|
|
}
|
|
|
|
void
|
|
KdmItem::paint(QPainter *p, const QRect &rect, bool background, bool primaryScreen)
|
|
{
|
|
if (!isVisible())
|
|
return;
|
|
if (background &&
|
|
(p->device()->width() < m_minScrWidth ||
|
|
p->device()->height() < m_minScrHeight))
|
|
return;
|
|
|
|
if (myWidget)
|
|
return;
|
|
|
|
QRect contentsRect = area.intersected(rect);
|
|
if (!contentsRect.isEmpty() &&
|
|
(!background || isBackground) &&
|
|
(paintOnScreen == ScrAll ||
|
|
((paintOnScreen == ScrGreeter) == primaryScreen)))
|
|
{
|
|
drawContents(p, contentsRect);
|
|
if (debugLevel & DEBUG_THEMING) {
|
|
// Draw bounding rect for this item
|
|
QPen pen(Qt::white);
|
|
pen.setCapStyle(Qt::FlatCap);
|
|
pen.setDashPattern(QVector<qreal>() << 5 << 6);
|
|
p->setPen(pen);
|
|
p->setBackgroundMode(Qt::OpaqueMode);
|
|
p->setBackground(Qt::black);
|
|
p->drawRect(area.x(), area.y(), area.width() - 1, area.height() - 1);
|
|
p->setBackgroundMode(Qt::TransparentMode);
|
|
}
|
|
}
|
|
|
|
// Dispatch paint events to children
|
|
forEachChild (itm)
|
|
itm->paint(p, rect, background, primaryScreen);
|
|
}
|
|
|
|
bool
|
|
KdmItem::childrenContain(int x, int y)
|
|
{
|
|
forEachVisibleChild (itm) {
|
|
if (itm->area.contains(x, y))
|
|
return true;
|
|
if (itm->childrenContain(x, y))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void
|
|
KdmItem::activateBuddy()
|
|
{
|
|
if (KdmItem *itm = themer()->findNode(buddy))
|
|
if (itm->myWidget) {
|
|
itm->myWidget->setFocus();
|
|
if (QLineEdit *le = qobject_cast<QLineEdit *>(itm->myWidget))
|
|
le->selectAll();
|
|
}
|
|
}
|
|
|
|
KdmItem *KdmItem::currentActive = 0;
|
|
|
|
void
|
|
KdmItem::mouseEvent(int x, int y, bool pressed, bool released)
|
|
{
|
|
if (!isVisible())
|
|
return;
|
|
|
|
ItemState oldState = state;
|
|
if (area.contains(x, y) || (isButton && childrenContain(x, y))) {
|
|
if (released && oldState == Sactive) {
|
|
if (isButton)
|
|
emit activated(objectName());
|
|
state = Sprelight;
|
|
currentActive = 0;
|
|
} else if (pressed && !buddy.isEmpty()) {
|
|
activateBuddy();
|
|
} else if (pressed || currentActive == this) {
|
|
state = Sactive;
|
|
currentActive = this;
|
|
} else if (!currentActive) {
|
|
state = Sprelight;
|
|
} else {
|
|
state = Snormal;
|
|
}
|
|
} else {
|
|
if (released)
|
|
currentActive = 0;
|
|
if (currentActive == this)
|
|
state = Sprelight;
|
|
else
|
|
state = Snormal;
|
|
}
|
|
if (oldState != state)
|
|
statusChanged(isButton);
|
|
|
|
if (!isButton)
|
|
forEachChild (itm)
|
|
itm->mouseEvent(x, y, pressed, released);
|
|
}
|
|
|
|
void
|
|
KdmItem::statusChanged(bool descend)
|
|
{
|
|
if (descend)
|
|
forEachChild (o) {
|
|
o->state = state;
|
|
o->statusChanged(descend);
|
|
}
|
|
}
|
|
|
|
// BEGIN protected inheritable
|
|
|
|
QSize
|
|
KdmItem::sizeHint()
|
|
{
|
|
if (myWidget)
|
|
return myWidget->sizeHint();
|
|
return QSize(
|
|
geom.size.x.type == DTpixel ? geom.size.x.val : 0,
|
|
geom.size.y.type == DTpixel ? geom.size.y.val : 0);
|
|
}
|
|
|
|
const QSize &
|
|
KdmItem::ensureHintedSize(QSize &hintedSize)
|
|
{
|
|
if (!hintedSize.isValid()) {
|
|
hintedSize = sizeHint();
|
|
debug() << "hinted" << hintedSize;
|
|
}
|
|
return hintedSize;
|
|
}
|
|
|
|
const QSize &
|
|
KdmItem::ensureBoxHint(QSize &boxHint, QStack<QSize> &parentSizes, QSize &hintedSize)
|
|
{
|
|
if (!boxHint.isValid()) {
|
|
if (myWidget || !boxManager)
|
|
boxHint = ensureHintedSize(hintedSize);
|
|
else
|
|
boxHint = boxManager->sizeHint(parentSizes);
|
|
debug() << "boxHint" << boxHint;
|
|
}
|
|
return boxHint;
|
|
}
|
|
|
|
static const QSize &
|
|
getParentSize(const QStack<QSize> &parentSizes, int levels)
|
|
{
|
|
int off = parentSizes.size() - 1 - levels;
|
|
if (off < 0) {
|
|
kError() << "Theme references element below the root.";
|
|
off = 0;
|
|
}
|
|
return parentSizes[off];
|
|
}
|
|
|
|
void
|
|
KdmItem::calcSize(
|
|
const DataPair &sz,
|
|
QStack<QSize> &parentSizes, QSize &hintedSize, QSize &boxHint,
|
|
QSize &io)
|
|
{
|
|
int w, h;
|
|
|
|
if (sz.x.type == DTpixel)
|
|
w = sz.x.val;
|
|
else if (sz.x.type == DTnpixel)
|
|
w = io.width() - sz.x.val;
|
|
else if (sz.x.type == DTpercent)
|
|
w = (getParentSize(parentSizes, sz.x.levels).width() * sz.x.val + 50) / 100;
|
|
else if (sz.x.type == DTbox)
|
|
w = ensureBoxHint(boxHint, parentSizes, hintedSize).width();
|
|
else
|
|
w = ensureHintedSize(hintedSize).width();
|
|
|
|
if (sz.y.type == DTpixel)
|
|
h = sz.y.val;
|
|
else if (sz.y.type == DTnpixel)
|
|
h = io.height() - sz.y.val;
|
|
else if (sz.y.type == DTpercent)
|
|
h = (getParentSize(parentSizes, sz.y.levels).height() * sz.y.val + 50) / 100;
|
|
else if (sz.y.type == DTbox)
|
|
h = ensureBoxHint(boxHint, parentSizes, hintedSize).height();
|
|
else
|
|
h = ensureHintedSize(hintedSize).height();
|
|
|
|
if (sz.x.type == DTscale && h && ensureHintedSize(hintedSize).height())
|
|
w = w * h / hintedSize.height();
|
|
else if (sz.y.type == DTscale && w && ensureHintedSize(hintedSize).width())
|
|
h = w * h / hintedSize.width();
|
|
|
|
io.setWidth(w);
|
|
io.setHeight(h);
|
|
}
|
|
|
|
void
|
|
KdmItem::sizingHint(QStack<QSize> &parentSizes, SizeHint &hint)
|
|
{
|
|
enter("Item::sizingHint") << objectName() << NoSpace << "parentSize #"
|
|
<< parentSizes.size() << Space << parentSizes.top();
|
|
|
|
QSize hintedSize, boxHint;
|
|
hint.min = hint.opt = hint.max = parentSizes.top();
|
|
calcSize(geom.size, parentSizes, hintedSize, boxHint, hint.opt);
|
|
calcSize(geom.minSize, parentSizes, hintedSize, boxHint, hint.min);
|
|
calcSize(geom.maxSize, parentSizes, hintedSize, boxHint, hint.max);
|
|
|
|
leave() << "size" << hint.opt << "min" << hint.min << "max" << hint.max;
|
|
|
|
hint.max = hint.max.expandedTo(hint.min); // if this triggers, the theme is bust
|
|
hint.opt = hint.opt.boundedTo(hint.max).expandedTo(hint.min);
|
|
|
|
// Note: no clipping to parent because this broke many themes!
|
|
}
|
|
|
|
QRect
|
|
KdmItem::placementHint(QStack<QSize> &sizes, const QSize &sz, const QPoint &offset)
|
|
{
|
|
const QSize &parentSize = sizes.top();
|
|
int x = offset.x(),
|
|
y = offset.y(),
|
|
w = parentSize.width(),
|
|
h = parentSize.height();
|
|
|
|
enter("Item::placementHint") << objectName() << NoSpace << "parentSize #"
|
|
<< sizes.size() << Space << parentSize << "size" << sz << "offset" << offset;
|
|
|
|
if (geom.pos.x.type == DTpixel)
|
|
x += geom.pos.x.val;
|
|
else if (geom.pos.x.type == DTnpixel)
|
|
x += w - geom.pos.x.val;
|
|
else if (geom.pos.x.type == DTpercent)
|
|
x += (w * geom.pos.x.val + 50) / 100;
|
|
|
|
if (geom.pos.y.type == DTpixel)
|
|
y += geom.pos.y.val;
|
|
else if (geom.pos.y.type == DTnpixel)
|
|
y += h - geom.pos.y.val;
|
|
else if (geom.pos.y.type == DTpercent)
|
|
y += (h * geom.pos.y.val + 50) / 100;
|
|
|
|
// defaults to center
|
|
int dx = sz.width() / 2, dy = sz.height() / 2;
|
|
|
|
// anchor the rect to an edge / corner
|
|
if (geom.anchor.length() > 0 && geom.anchor.length() < 3) {
|
|
if (geom.anchor.indexOf('n') >= 0)
|
|
dy = 0;
|
|
if (geom.anchor.indexOf('s') >= 0)
|
|
dy = sz.height();
|
|
if (geom.anchor.indexOf('w') >= 0)
|
|
dx = 0;
|
|
if (geom.anchor.indexOf('e') >= 0)
|
|
dx = sz.width();
|
|
}
|
|
leave() << "x:" << x << "dx:" << dx << "y:" << y << "dy:" << dy;
|
|
y -= dy;
|
|
x -= dx;
|
|
|
|
return QRect(x, y, sz.width(), sz.height());
|
|
}
|
|
|
|
QRect
|
|
KdmItem::placementHint(QStack<QSize> &sizes, const QPoint &offset)
|
|
{
|
|
SizeHint sh;
|
|
sizingHint(sizes, sh);
|
|
return placementHint(sizes, sh.opt, offset);
|
|
}
|
|
|
|
// END protected inheritable
|
|
|
|
|
|
void
|
|
KdmItem::showStructure(const QString &pfx)
|
|
{
|
|
{
|
|
QDebug ds(QtDebugMsg);
|
|
if (!pfx.isEmpty())
|
|
ds << (qPrintable(pfx) + 1);
|
|
ds << objectName() << qPrintable(itemType) << area;
|
|
}
|
|
if (!m_children.isEmpty()) {
|
|
QString npfx(pfx);
|
|
npfx.replace('\\', ' ').replace('-', ' ');
|
|
for (int i = 0; i < m_children.count() - 1; i++)
|
|
m_children[i]->showStructure(npfx + " |-");
|
|
m_children[m_children.count() - 1]->showStructure(npfx + " \\-");
|
|
}
|
|
}
|
|
|
|
void
|
|
KdmItem::addChildItem(KdmItem *item)
|
|
{
|
|
m_children.append(item);
|
|
switch (currentManager) {
|
|
case MNone: // fallback to the 'fixed' case
|
|
setFixedLayout();
|
|
case MFixed:
|
|
fixedManager->addItem(item);
|
|
break;
|
|
case MBox:
|
|
boxManager->addItem(item);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
KdmItem::setBoxLayout(const QDomNode &node)
|
|
{
|
|
if (!boxManager)
|
|
boxManager = new KdmLayoutBox(node);
|
|
currentManager = MBox;
|
|
}
|
|
|
|
void
|
|
KdmItem::setFixedLayout(const QDomNode &node)
|
|
{
|
|
if (!fixedManager)
|
|
fixedManager = new KdmLayoutFixed(node);
|
|
currentManager = MFixed;
|
|
}
|
|
|
|
#include "kdmitem.moc"
|