OTHER: skin handling cleanups
This commit is contained in:
parent
8509c3d15d
commit
e99f0e4325
9 changed files with 161 additions and 133 deletions
|
@ -88,9 +88,7 @@ MainDisplay::MainDisplay (MainWindow *parent) : SkinDisplay(parent)
|
|||
m_clutterbar = new ClutterBar (this);
|
||||
m_clutterbar->move (10, 22);
|
||||
|
||||
m_posbar = new PosBar (this, Skin::POSBAR,
|
||||
Skin::POSBAR_BTN_0,
|
||||
Skin::POSBAR_BTN_1);
|
||||
m_posbar = new PosBar (this);
|
||||
m_posbar->move (skin->getPos (Skin::SLIDER_POSBAR_BGS));
|
||||
connect (m_posbar, SIGNAL (sliderMoved (int)),
|
||||
client->xplayback (), SLOT (seekMs (int)));
|
||||
|
@ -164,11 +162,10 @@ MainDisplay::setPixmaps (Skin *skin)
|
|||
|
||||
/* update Sliders */
|
||||
m_vslider->setBackground (skin->getBackgrounds (Skin::SLIDER_VOLUMEBAR_BGS));
|
||||
m_vslider->setSliders (skin->getItem (Skin::VOLBAR_BTN_0),
|
||||
skin->getItem (Skin::VOLBAR_BTN_1));
|
||||
m_vslider->setButton (skin->getButton (Skin::SLIDER_VOLUMEBAR_BUTTON));
|
||||
|
||||
m_bslider->setBackground (skin->getBackgrounds (Skin::SLIDER_BALANCEBAR_BGS));
|
||||
m_bslider->setSliders (skin->getItem (Skin::BALANCE_BTN_0),
|
||||
skin->getItem (Skin::BALANCE_BTN_1));
|
||||
m_bslider->setButton (skin->getButton (Skin::SLIDER_BALANCEBAR_BUTTON));
|
||||
|
||||
/* update some other widgets */
|
||||
m_time->setPixmaps (skin->getNumbers ());
|
||||
|
|
|
@ -20,13 +20,8 @@
|
|||
|
||||
#include <QWidget>
|
||||
|
||||
PosBar::PosBar (QWidget *parent, uint bg, uint bnormal, uint bpressed)
|
||||
: PixmapSlider (parent)
|
||||
PosBar::PosBar (QWidget *parent) : PixmapSlider (parent)
|
||||
{
|
||||
m_slider_normal = bnormal;
|
||||
m_slider_pressed = bpressed;
|
||||
m_bg = bg;
|
||||
|
||||
connect (SkinManager::instance (), SIGNAL (skinChanged (Skin *)),
|
||||
this, SLOT (setPixmaps (Skin *)));
|
||||
|
||||
|
@ -41,17 +36,11 @@ PosBar::PosBar (QWidget *parent, uint bg, uint bnormal, uint bpressed)
|
|||
void
|
||||
PosBar::setPixmaps (Skin *skin)
|
||||
{
|
||||
QPixmap pixmap = skin->getItem (m_bg);
|
||||
QPixmap pixmap = skin->getItem (Skin::POSBAR);
|
||||
setBackground (pixmap);
|
||||
setFixedSize (248, pixmap.height ());
|
||||
|
||||
if ( !skin->getItem(m_slider_normal).isNull() &&
|
||||
!skin->getItem(m_slider_pressed).isNull()) {
|
||||
setSliders (skin->getItem(m_slider_normal),
|
||||
skin->getItem(m_slider_pressed));
|
||||
} else {
|
||||
setSliders (QPixmap (), QPixmap ());
|
||||
}
|
||||
setButton (skin->getButton (Skin::SLIDER_POSBAR_BUTTON));
|
||||
|
||||
update ();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* This file is a part of Promoe, an XMMS2 Client.
|
||||
*
|
||||
* Copyright (C) 2005-2008 XMMS2 Team
|
||||
* Copyright (C) 2005-2010 XMMS2 Team
|
||||
*
|
||||
* 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
|
||||
|
@ -25,16 +25,11 @@ class PosBar : public PixmapSlider
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PosBar (QWidget *parent, uint bg, uint bnormal, uint bpressed);
|
||||
PosBar (QWidget *parent);
|
||||
~PosBar () { }
|
||||
|
||||
|
||||
public slots:
|
||||
void setPixmaps (Skin *skin);
|
||||
|
||||
private:
|
||||
uint m_slider_normal;
|
||||
uint m_slider_pressed;
|
||||
uint m_bg;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -146,8 +146,11 @@ Skin::handle_posbar (const QPixmap &img)
|
|||
const int h = qMin (10, img.height ());
|
||||
m_sizes[SLIDER_POSBAR_BGS] = QSize (248, h);
|
||||
m_items[POSBAR] = img.copy (0, 0, 248, h);
|
||||
m_items[POSBAR_BTN_0] = img.copy (248, 0, 29, h);
|
||||
m_items[POSBAR_BTN_1] = img.copy (278, 0, 29, h);
|
||||
|
||||
ButtonPixmaps button;
|
||||
button.addPixmap (img.copy (248, 0, 29, h), ButtonPixmaps::Normal);
|
||||
button.addPixmap (img.copy (278, 0, 29, h), ButtonPixmaps::Pressed);
|
||||
m_buttons[SLIDER_POSBAR_BUTTON] = button;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -165,10 +168,11 @@ Skin::handle_volume (const QPixmap &img)
|
|||
m_backgrounds[SLIDER_VOLUMEBAR_BGS] = list;
|
||||
|
||||
if (img.height() > 421) {
|
||||
m_items[VOLBAR_BTN_1] = img.copy (0, 422, 14,
|
||||
qMin (11, img.height () - 422));
|
||||
m_items[VOLBAR_BTN_0] = img.copy (15, 422, 14,
|
||||
qMin (11, img.height () - 422));
|
||||
const int h = qMin (11, img.height () - 422);
|
||||
ButtonPixmaps button;
|
||||
button.addPixmap (img.copy (0, 422, 14, h), ButtonPixmaps::Normal);
|
||||
button.addPixmap (img.copy (15, 422, 14, h), ButtonPixmaps::Pressed);
|
||||
m_buttons[SLIDER_VOLUMEBAR_BUTTON] = button;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -194,10 +198,11 @@ Skin::handle_balance (const QPixmap &img)
|
|||
m_backgrounds[SLIDER_BALANCEBAR_BGS] = list;
|
||||
|
||||
if (img.height() > 421) {
|
||||
m_items[BALANCE_BTN_1] = img.copy(0, 422, 14,
|
||||
qMin (11, img.height () - 422));
|
||||
m_items[BALANCE_BTN_0] = img.copy(15, 422, 14,
|
||||
qMin (11, img.height () - 422));
|
||||
const int h = qMin (11, img.height () - 422);
|
||||
ButtonPixmaps button;
|
||||
button.addPixmap (img.copy (0, 422, 14, h), ButtonPixmaps::Normal);
|
||||
button.addPixmap (img.copy (15, 422, 14, h), ButtonPixmaps::Pressed);
|
||||
m_buttons[SLIDER_BALANCEBAR_BUTTON] = button;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
|
||||
#include "pixmapbutton.h"
|
||||
#include "buttonpixmaps.h"
|
||||
|
||||
class QIODevice;
|
||||
|
||||
|
@ -39,13 +39,14 @@ class Skin : public QObject
|
|||
Skin (const QString &url);
|
||||
Skin (Skin *other, const QString &url = "");
|
||||
|
||||
const bool isValid () const {return m_valid;}
|
||||
const bool isValid () const
|
||||
{ return m_valid; }
|
||||
|
||||
static const QPixmap getPixmap (const QString&, const QString&);
|
||||
static const QPixmap getMainPixmap (const QString& path);
|
||||
|
||||
const QSize getSize (uint item) const
|
||||
{ return m_sizes.value (item); }
|
||||
{ return m_sizes.value (item); }
|
||||
const QPoint getPos (uint item) const
|
||||
{ return m_positions.value (item); }
|
||||
|
||||
|
@ -54,17 +55,19 @@ class Skin : public QObject
|
|||
const PixmapMap getSmallNumbers () const
|
||||
{ return m_smallNumbers; }
|
||||
|
||||
const PBPixmaps getButton (int button) const
|
||||
const ButtonPixmaps getButton (int button) const
|
||||
{ return m_buttons.value (button); }
|
||||
const QPixmapList getBackgrounds (uint item) const
|
||||
{ return m_backgrounds.value(item); };
|
||||
const PixmapMap getPixmapFont () const
|
||||
{ return m_letterMap; }
|
||||
|
||||
const QPixmap getItem (uint part) const { return m_items.value (part); }
|
||||
const QPixmap getItem (uint part) const
|
||||
{ return m_items.value (part); }
|
||||
const QPixmap getPls (uint part) const
|
||||
{ return m_playlist.value (part); }
|
||||
const QPixmap getLetter (uint c) const { return m_letterMap.value (c); }
|
||||
const QPixmap getLetter (uint c) const
|
||||
{ return m_letterMap.value (c); }
|
||||
const QByteArray getPLeditValue (QByteArray c) const
|
||||
{ return m_pledit_txt.value(c); }
|
||||
|
||||
|
@ -95,7 +98,7 @@ class Skin : public QObject
|
|||
QString m_skinname;
|
||||
QString m_path;
|
||||
|
||||
QMap<int, PBPixmaps> m_buttons;
|
||||
QMap<int, ButtonPixmaps> m_buttons;
|
||||
QMap<uint, QPixmapList> m_backgrounds;
|
||||
|
||||
QMap<int, QPixmap> m_numbers;
|
||||
|
@ -150,10 +153,13 @@ class Skin : public QObject
|
|||
/* Sliders */
|
||||
SLIDER_POSBAR,
|
||||
SLIDER_POSBAR_BGS,
|
||||
SLIDER_POSBAR_BUTTON,
|
||||
SLIDER_VOLUMEBAR,
|
||||
SLIDER_VOLUMEBAR_BGS,
|
||||
SLIDER_VOLUMEBAR_BUTTON,
|
||||
SLIDER_BALANCEBAR,
|
||||
SLIDER_BALANCEBAR_BGS,
|
||||
SLIDER_BALANCEBAR_BUTTON,
|
||||
SLIDER_EQUALIZER,
|
||||
SLIDER_EQUALIZER_BGS,
|
||||
// };
|
||||
|
@ -192,12 +198,6 @@ class Skin : public QObject
|
|||
EQ_WIN_BAR_BTN_0,
|
||||
EQ_WIN_BAR_BTN_1,
|
||||
POSBAR,
|
||||
POSBAR_BTN_0,
|
||||
POSBAR_BTN_1,
|
||||
VOLBAR_BTN_0,
|
||||
VOLBAR_BTN_1,
|
||||
BALANCE_BTN_0,
|
||||
BALANCE_BTN_1,
|
||||
};
|
||||
|
||||
enum PlaylistParts {
|
||||
|
|
89
src/widgets/buttonpixmaps.h
Normal file
89
src/widgets/buttonpixmaps.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* This file is a part of Promoe, an XMMS2 CLient
|
||||
*
|
||||
* Copyright (C) 2008-2010 XMMS2 Team
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __BUTTONPIXMAPS_H__
|
||||
#define __BUTTONPIXMAPS_H__
|
||||
|
||||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
|
||||
typedef QMap <int, QPixmap> PixmapMap;
|
||||
|
||||
/*
|
||||
* QIcon::Normal for normal apperance
|
||||
* QIcon::Active for pressed state
|
||||
*
|
||||
* QIcon::Off for uncecked state
|
||||
* QIcon::On for checked state
|
||||
*
|
||||
* only QIcon::Normal QIcon::Off combination is necessary
|
||||
*/
|
||||
class ButtonPixmaps
|
||||
{
|
||||
public:
|
||||
ButtonPixmaps () :
|
||||
m_pixmaps() {}
|
||||
ButtonPixmaps (const ButtonPixmaps &p) :
|
||||
m_pixmaps(p.m_pixmaps) {}
|
||||
|
||||
|
||||
enum Mode {
|
||||
Normal = 0, // Used when button is in active Window
|
||||
Inactive = 1, // Used when button is in inactive Window
|
||||
Pressed = 2 // used when button is pressed
|
||||
};
|
||||
|
||||
enum State {
|
||||
Unchecked = 0, // used when button is unchecked
|
||||
Checked = 1 // used when button is checked
|
||||
};
|
||||
|
||||
void addPixmap (const QPixmap & pixmap, Mode m = Normal,
|
||||
State s = Unchecked) {
|
||||
m_pixmaps[getKey(m, s)] = pixmap;
|
||||
if (!m_pixmaps.contains (getKey (Normal, Unchecked))) {
|
||||
m_pixmaps[getKey (Normal, Unchecked)] = pixmap;
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap pixmap (Mode m = Normal, State s = Unchecked) const {
|
||||
if (m_pixmaps.contains (getKey (m, s))) {
|
||||
return m_pixmaps.value (getKey (m, s));
|
||||
|
||||
} else if (s == Checked && m != Normal &&
|
||||
m_pixmaps.contains (getKey (Normal, s))) {
|
||||
return m_pixmaps.value (getKey (Normal, s));
|
||||
} else {
|
||||
return m_pixmaps.value (getKey (Normal, Unchecked));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ButtonPixmaps & operator= (const ButtonPixmaps & p) {
|
||||
m_pixmaps = p.m_pixmaps;
|
||||
}
|
||||
|
||||
protected:
|
||||
PixmapMap m_pixmaps;
|
||||
|
||||
// get the key to be used in the PixmapMap
|
||||
inline int getKey (Mode m, State s) const { return (m + s*3); }
|
||||
};
|
||||
|
||||
typedef ButtonPixmaps PBPixmaps;
|
||||
typedef ButtonPixmaps PixmapButtonPixmaps;
|
||||
|
||||
#endif
|
|
@ -21,75 +21,13 @@
|
|||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
|
||||
#include "buttonpixmaps.h"
|
||||
|
||||
typedef QMap <int, QPixmap> PixmapMap;
|
||||
|
||||
class QPaintEvent;
|
||||
class QWidget;
|
||||
|
||||
/*
|
||||
* QIcon::Normal for normal apperance
|
||||
* QIcon::Active for pressed state
|
||||
*
|
||||
* QIcon::Off for uncecked state
|
||||
* QIcon::On for checked state
|
||||
*
|
||||
* only QIcon::Normal QIcon::Off combination is necessary
|
||||
*/
|
||||
class PixmapButtonPixmaps
|
||||
{
|
||||
public:
|
||||
PixmapButtonPixmaps () :
|
||||
m_pixmaps() {}
|
||||
PixmapButtonPixmaps (const PixmapButtonPixmaps &p) :
|
||||
m_pixmaps(p.m_pixmaps) {}
|
||||
|
||||
|
||||
enum Mode {
|
||||
Normal = 0, // Used when button is in active Window
|
||||
Inactive = 1, // Used when button is in inactive Window
|
||||
Pressed = 2 // used when button is pressed
|
||||
};
|
||||
|
||||
enum State {
|
||||
Unchecked = 0, // used when button is unchecked
|
||||
Checked = 1 // used when button is checked
|
||||
};
|
||||
|
||||
void addPixmap (const QPixmap & pixmap, Mode m = Normal,
|
||||
State s = Unchecked) {
|
||||
m_pixmaps[getKey(m, s)] = pixmap;
|
||||
if (!m_pixmaps.contains (getKey (Normal, Unchecked))) {
|
||||
m_pixmaps[getKey (Normal, Unchecked)] = pixmap;
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap pixmap (Mode m = Normal, State s = Unchecked) const {
|
||||
if (m_pixmaps.contains (getKey (m, s))) {
|
||||
return m_pixmaps.value (getKey (m, s));
|
||||
|
||||
} else if (s == Checked && m != Normal &&
|
||||
m_pixmaps.contains (getKey (Normal, s))) {
|
||||
return m_pixmaps.value (getKey (Normal, s));
|
||||
} else {
|
||||
return m_pixmaps.value (getKey (Normal, Unchecked));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PixmapButtonPixmaps & operator= (const PixmapButtonPixmaps & p) {
|
||||
m_pixmaps = p.m_pixmaps;
|
||||
}
|
||||
|
||||
protected:
|
||||
PixmapMap m_pixmaps;
|
||||
|
||||
// get the key to be used in the PixmapMap
|
||||
inline int getKey (Mode m, State s) const { return (m + s*3); }
|
||||
};
|
||||
|
||||
typedef PixmapButtonPixmaps PBPixmaps;
|
||||
|
||||
|
||||
class PixmapButton : public QAbstractButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -98,7 +36,7 @@ class PixmapButton : public QAbstractButton
|
|||
PixmapButton (QWidget *parent) : QAbstractButton (parent) {}
|
||||
~PixmapButton () {};
|
||||
|
||||
void setPixmaps (const PixmapButtonPixmaps & p);
|
||||
void setPixmaps (const ButtonPixmaps & p);
|
||||
|
||||
protected:
|
||||
void paintEvent ( QPaintEvent * event );
|
||||
|
|
|
@ -43,11 +43,17 @@ PixmapSlider::setBackground (const QPixmapList &list)
|
|||
m_background_index = -1;
|
||||
}
|
||||
|
||||
void
|
||||
PixmapSlider::setButton (const ButtonPixmaps &p)
|
||||
{
|
||||
m_button = p;
|
||||
}
|
||||
|
||||
void
|
||||
PixmapSlider::setSliders (QPixmap normal, QPixmap pressed)
|
||||
{
|
||||
m_normal = normal;
|
||||
m_pressed = pressed;
|
||||
m_button.addPixmap (normal, ButtonPixmaps::Normal);
|
||||
m_button.addPixmap (pressed, ButtonPixmaps::Pressed);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -107,10 +113,11 @@ int
|
|||
PixmapSlider::sliderMovePosition (QMouseEvent *event)
|
||||
{
|
||||
int ret;
|
||||
QPixmap p = m_button.pixmap (ButtonPixmaps::Pressed);
|
||||
if (orientation () == Qt::Vertical) {
|
||||
ret = sliderValueFromPosition (event->y() - m_pressed.height () /2);
|
||||
ret = sliderValueFromPosition (event->y() - p.height () /2);
|
||||
} else {
|
||||
ret = sliderValueFromPosition (event->x() - m_pressed.width () /2);
|
||||
ret = sliderValueFromPosition (event->x() - p.width () /2);
|
||||
}
|
||||
|
||||
// Make sliders snap to center. Usefull for equalizer sliders and balance
|
||||
|
@ -149,8 +156,9 @@ PixmapSlider::paintEvent (QPaintEvent *event)
|
|||
p.drawPixmap (0, 0, bg.width(), bg.height(), bg);
|
||||
}
|
||||
// draw slider
|
||||
QPixmap *slider = isSliderDown () ? &m_pressed : &m_normal;
|
||||
QRect rect (slider->rect ());
|
||||
QPixmap slider = m_button.pixmap (isSliderDown () ? ButtonPixmaps::Pressed
|
||||
: ButtonPixmaps::Normal);
|
||||
QRect rect (slider.rect ());
|
||||
if (orientation () == Qt::Vertical) {
|
||||
rect.moveTop (sliderPositionFromValue () + m_slider_offset.y ());
|
||||
rect.moveLeft (m_slider_offset.x ());
|
||||
|
@ -158,7 +166,7 @@ PixmapSlider::paintEvent (QPaintEvent *event)
|
|||
rect.moveLeft (sliderPositionFromValue () + m_slider_offset.x ());
|
||||
rect.moveTop (m_slider_offset.y ());
|
||||
}
|
||||
p.drawPixmap (rect , *slider, slider->rect ());
|
||||
p.drawPixmap (rect , slider, slider.rect ());
|
||||
p.end ();
|
||||
}
|
||||
|
||||
|
@ -166,10 +174,11 @@ int
|
|||
PixmapSlider::sliderPositionFromValue ()
|
||||
{
|
||||
int span;
|
||||
QPixmap p = m_button.pixmap (ButtonPixmaps::Normal);
|
||||
if (orientation () == Qt::Vertical) {
|
||||
span = height () - m_normal.height ();
|
||||
span = height () - p.height ();
|
||||
} else {
|
||||
span = width () - m_normal.width ();
|
||||
span = width () - p.width ();
|
||||
}
|
||||
|
||||
return QStyle::sliderPositionFromValue (minimum (), maximum (),
|
||||
|
@ -181,10 +190,11 @@ int
|
|||
PixmapSlider::sliderValueFromPosition (int pos)
|
||||
{
|
||||
int span;
|
||||
QPixmap p = m_button.pixmap (ButtonPixmaps::Normal);
|
||||
if (orientation () == Qt::Vertical) {
|
||||
span = height () - m_normal.height ();
|
||||
span = height () - p.height ();
|
||||
} else {
|
||||
span = width () - m_normal.width ();
|
||||
span = width () - p.width ();
|
||||
}
|
||||
|
||||
return QStyle::sliderValueFromPosition (minimum (), maximum (), pos,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* This file is a part of Promoe, an XMMS2 CLient
|
||||
*
|
||||
* Copyright (C) 2008 XMMS2 Team
|
||||
* Copyright (C) 2008-2010 XMMS2 Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -21,6 +21,8 @@
|
|||
#include <QList>
|
||||
#include <QPoint>
|
||||
|
||||
#include "buttonpixmaps.h"
|
||||
|
||||
class QWidget;
|
||||
class QPixmap;
|
||||
class QPaintEvent;
|
||||
|
@ -41,9 +43,13 @@ class PixmapSlider : public QAbstractSlider
|
|||
void setBackground (const QPixmapList &);
|
||||
QPixmapList backgrounds () const { return m_backgrounds; }
|
||||
|
||||
void setButton (const ButtonPixmaps &);
|
||||
|
||||
void setSliders (QPixmap normal, QPixmap pressed = QPixmap ());
|
||||
QPixmap normalSlider () const { return m_normal; }
|
||||
QPixmap pressedSlider () const { return m_pressed; }
|
||||
QPixmap normalSlider () const
|
||||
{ return m_button.pixmap (ButtonPixmaps::Normal); }
|
||||
QPixmap pressedSlider () const
|
||||
{ return m_button.pixmap (ButtonPixmaps::Pressed); }
|
||||
|
||||
void setSliderOffset (QPoint offset) { m_slider_offset = offset; }
|
||||
|
||||
|
@ -63,8 +69,7 @@ class PixmapSlider : public QAbstractSlider
|
|||
|
||||
private:
|
||||
QPixmapList m_backgrounds;
|
||||
QPixmap m_normal;
|
||||
QPixmap m_pressed;
|
||||
ButtonPixmaps m_button;
|
||||
|
||||
QPoint m_slider_offset;
|
||||
int m_background_index;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue