mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 14:16:09 -06:00
296 lines
5.6 KiB
C++
296 lines
5.6 KiB
C++
#include "CtrlLib.h"
|
|
|
|
namespace Upp {
|
|
|
|
CH_STYLE(Splitter, Style, StyleDefault)
|
|
{
|
|
width = Ctrl::HorzLayoutZoom(4);
|
|
vert[0] = horz[0] = SColorFace();
|
|
vert[1] = horz[1] = GUI_GlobalStyle() >= GUISTYLE_XP ? Blend(SColorHighlight, SColorFace)
|
|
: SColorShadow();
|
|
dots = true;
|
|
}
|
|
|
|
int Splitter::ClientToPos(Point p) const
|
|
{
|
|
return minmax(vert ? 10000 * p.y / GetSize().cy : 10000 * p.x / GetSize().cx, 0, 9999);
|
|
}
|
|
|
|
int Splitter::PosToClient(int pos) const
|
|
{
|
|
return (vert ? GetSize().cy : GetSize().cx) * pos / 10000;
|
|
}
|
|
|
|
void Splitter::Layout() {
|
|
Size sz = GetSize();
|
|
int count = GetChildCount();
|
|
if(count == 0)
|
|
return;
|
|
mins.SetCount(count, 0);
|
|
minpx.SetCount(count, 0);
|
|
count--;
|
|
if(pos.GetCount() < count) {
|
|
pos.SetCount(count, 0);
|
|
for(int i = 0; i < count; i++)
|
|
pos[i] = (i + 1) * 10000 / (count + 1);
|
|
}
|
|
if(style >= 0) {
|
|
int i = 0;
|
|
for(Ctrl *q = GetFirstChild(); q; q = q->GetNext()) {
|
|
if(style == i)
|
|
q->SizePos().Show();
|
|
else
|
|
q->Hide();
|
|
i++;
|
|
}
|
|
return;
|
|
}
|
|
|
|
int lw = chstyle->width >> 1;
|
|
int rw = chstyle->width - lw;
|
|
|
|
int i = 0;
|
|
for(Ctrl *q = GetFirstChild(); q; q = q->GetNext()) {
|
|
int lo = i > 0 ? PosToClient(pos[i - 1]) + rw : 0;
|
|
int hi = i < count ? PosToClient(pos[i]) - lw : vert ? sz.cy : sz.cx;
|
|
q->Show();
|
|
if(vert)
|
|
q->SetRect(0, lo, sz.cx, hi - lo);
|
|
else
|
|
q->SetRect(lo, 0, hi - lo, sz.cy);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
int Splitter::GetSplitWidth() const
|
|
{
|
|
return chstyle->width;
|
|
}
|
|
|
|
void Splitter::PaintDots(Draw& w, const Rect& r, bool vert)
|
|
{
|
|
int x = r.left + r.GetWidth() / 2;
|
|
int y = r.top + r.GetHeight() / 2;
|
|
(vert ? x : y) -= 8 * 4;
|
|
for(int i = 0; i < 16; i++) {
|
|
w.DrawRect(x - 1, y - 1, 1, 1, SColorShadow());
|
|
w.DrawRect(x, y, 1, 1, SColorShadow());
|
|
(vert ? x : y) += 4;
|
|
}
|
|
}
|
|
|
|
void Splitter::Paint(Draw& w) {
|
|
Size sz = GetSize();
|
|
if(!IsTransparent())
|
|
w.DrawRect(sz, SColorFace);
|
|
const Value *ch = vert ? chstyle->vert : chstyle->horz;
|
|
if(style < 0)
|
|
for(int i = 0; i < pos.GetCount(); i++) {
|
|
int p = PosToClient(pos[i]) - (chstyle->width >> 1);
|
|
Rect r = vert ? RectC(0, p, sz.cx, chstyle->width) : RectC(p, 0, chstyle->width, sz.cy);
|
|
if(HasCapture() && i == mouseindex)
|
|
ChPaint(w, r, ch[1]);
|
|
else
|
|
if(!IsTransparent())
|
|
ChPaint(w, r, ch[0]);
|
|
if(chstyle->dots)
|
|
PaintDots(w, r, vert);
|
|
}
|
|
}
|
|
|
|
void Splitter::MouseMove(Point p, dword) {
|
|
if(HasCapture() && mouseindex >= 0 && mouseindex < pos.GetCount()) {
|
|
SetPos(ClientToPos(p), mouseindex);
|
|
Refresh();
|
|
WhenAction();
|
|
}
|
|
}
|
|
|
|
void Splitter::LeftDown(Point p, dword) {
|
|
SetCapture();
|
|
Refresh();
|
|
mouseindex = FindIndex(p);
|
|
}
|
|
|
|
int Splitter::FindIndex(Point client) const {
|
|
int best = -1;
|
|
int maxdist = chstyle->width;
|
|
for(int i = 0; i < pos.GetCount(); i++) {
|
|
int dist = abs((vert ? client.y : client.x) - PosToClient(pos[i]));
|
|
if(dist <= maxdist) {
|
|
best = i;
|
|
maxdist = abs(dist);
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
|
|
void Splitter::LeftUp(Point p, dword keyflags) {
|
|
if(HasCapture())
|
|
WhenSplitFinish();
|
|
ReleaseCapture();
|
|
Refresh();
|
|
}
|
|
|
|
Image Splitter::CursorImage(Point p, dword) {
|
|
return FindIndex(p) < 0 ? Image::Arrow() : vert ? Image::SizeVert() : Image::SizeHorz();
|
|
}
|
|
|
|
int Splitter::GetMins(int i) const
|
|
{
|
|
int min1 = (i < mins.GetCount() ? mins[i] : 0);
|
|
int min2 = 0;
|
|
int cx = IsVert() ? GetSize().cy : GetSize().cx;
|
|
if(cx)
|
|
min2 = (i < minpx.GetCount() ? minpx[i] : 0) * 10000 / cx;
|
|
return max(min1, min2);
|
|
}
|
|
|
|
Splitter& Splitter::SetPos(int p, int i) {
|
|
int l = (i > 0 && i - 1 < pos.GetCount() ? pos[i - 1] : 0) + GetMins(i);
|
|
int h = (i + 1 < pos.GetCount() ? pos[i + 1] : 10000) - GetMins(i + 1);
|
|
pos.At(i) = minmax(p, l, h);
|
|
Layout();
|
|
return *this;
|
|
}
|
|
|
|
void Splitter::Zoom(int i)
|
|
{
|
|
style = i;
|
|
Layout();
|
|
}
|
|
|
|
Splitter& Splitter::Vert(Ctrl& top, Ctrl& bottom)
|
|
{
|
|
vert = true;
|
|
Set(top, bottom);
|
|
return *this;
|
|
}
|
|
|
|
Splitter& Splitter::Horz(Ctrl& left, Ctrl& right)
|
|
{
|
|
vert = false;
|
|
Set(left, right);
|
|
return *this;
|
|
}
|
|
|
|
void Splitter::Set(Ctrl& l, Ctrl& r)
|
|
{
|
|
Clear();
|
|
*this << l << r;
|
|
Layout();
|
|
}
|
|
|
|
void Splitter::Add(Ctrl& pane)
|
|
{
|
|
Ctrl::Add(pane);
|
|
Layout();
|
|
}
|
|
|
|
void Splitter::Insert(int ii, Ctrl& pane)
|
|
{
|
|
if(ii >= GetCount())
|
|
Add(pane);
|
|
else {
|
|
Ctrl::AddChildBefore(&pane, GetIndexChild(ii));
|
|
pos.Clear();
|
|
Layout();
|
|
}
|
|
}
|
|
|
|
void Splitter::Swap(Ctrl& child, Ctrl& newctrl)
|
|
{
|
|
newctrl.SetRect(child.GetRect());
|
|
Ctrl::AddChildBefore(&newctrl, &child);
|
|
Ctrl::RemoveChild(&child);
|
|
}
|
|
|
|
void Splitter::Serialize(Stream& s) {
|
|
int version = 0x02;
|
|
s / version;
|
|
if(version <= 1) {
|
|
int p = GetPos(0);
|
|
s % p;
|
|
SetPos(p, 0);
|
|
}
|
|
else
|
|
s % pos;
|
|
if(version >= 0x01) {
|
|
s / style;
|
|
if(version == 0x01 && style == 3)
|
|
style = -1;
|
|
}
|
|
if(s.IsLoading()) {
|
|
for(int i = 0; i < pos.GetCount(); i++)
|
|
if(pos[i] < 0 || pos[i] > 10000) {
|
|
pos.Clear();
|
|
s.LoadError();
|
|
}
|
|
if(style >= GetChildCount()) {
|
|
style = -1;
|
|
s.LoadError();
|
|
}
|
|
Layout();
|
|
}
|
|
}
|
|
|
|
void Splitter::Remove(Ctrl& ctrl)
|
|
{
|
|
int n = 0;
|
|
Ctrl *c = GetFirstChild();
|
|
while(c){
|
|
if(c == &ctrl){
|
|
if(c->GetNext())
|
|
pos.Remove(n);
|
|
else
|
|
if(n >= 1)
|
|
pos.Remove(n-1);
|
|
mins.Remove(n);
|
|
minpx.Remove(n);
|
|
RemoveChild(c);
|
|
break;
|
|
}
|
|
c = c->GetNext();
|
|
n++;
|
|
}
|
|
}
|
|
|
|
void Splitter::Clear() {
|
|
while(GetFirstChild())
|
|
RemoveChild(GetFirstChild());
|
|
pos.Clear();
|
|
mins.Clear();
|
|
minpx.Clear();
|
|
}
|
|
|
|
void Splitter::Reset() {
|
|
Clear();
|
|
style = -1;
|
|
vert = false;
|
|
}
|
|
|
|
Splitter& Splitter::SetStyle(const Style& s)
|
|
{
|
|
if(chstyle != &s) {
|
|
chstyle = &s;
|
|
RefreshLayout();
|
|
Refresh();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
Splitter::Splitter() {
|
|
chstyle = NULL;
|
|
style = -1;
|
|
vert = false;
|
|
mouseindex = -1;
|
|
pos.Add(5000);
|
|
SetFrame(NullFrame());
|
|
NoWantFocus();
|
|
VSizePos(0, 0).HSizePos(0, 0);
|
|
SetStyle(StyleDefault());
|
|
}
|
|
|
|
Splitter::~Splitter() {}
|
|
|
|
}
|