267 lines
6.0 KiB
C++
267 lines
6.0 KiB
C++
// view.cpp
|
|
//
|
|
// Copyright (C) 2001-2019, Celestia Development 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.
|
|
|
|
#include <celengine/rectangle.h>
|
|
#include <celengine/render.h>
|
|
#include <celutil/color.h>
|
|
#include "view.h"
|
|
|
|
#include<iostream>
|
|
|
|
View::View(View::Type _type,
|
|
Renderer *_renderer,
|
|
Observer *_observer,
|
|
float _x, float _y,
|
|
float _width, float _height) :
|
|
type(_type),
|
|
renderer(_renderer),
|
|
observer(_observer),
|
|
x(_x),
|
|
y(_y),
|
|
width(_width),
|
|
height(_height)
|
|
{
|
|
}
|
|
|
|
void View::mapWindowToView(float wx, float wy, float& vx, float& vy) const
|
|
{
|
|
vx = (wx - x) / width;
|
|
vy = (wy + (y + height - 1)) / height;
|
|
vx = (vx - 0.5f) * (width / height);
|
|
vy = 0.5f - vy;
|
|
}
|
|
|
|
void View::walkTreeResize(View* sibling, int sign)
|
|
{
|
|
float ratio;
|
|
switch (parent->type)
|
|
{
|
|
case View::HorizontalSplit:
|
|
ratio = parent->height / (parent->height - height);
|
|
sibling->height *= ratio;
|
|
if (sign == 1)
|
|
{
|
|
sibling->y = parent->y + (sibling->y - parent->y) * ratio;
|
|
}
|
|
else
|
|
{
|
|
sibling->y = parent->y + (sibling->y - (y + height)) * ratio;
|
|
}
|
|
break;
|
|
|
|
case View::VerticalSplit:
|
|
ratio = parent->width / (parent->width - width);
|
|
sibling->width *= ratio;
|
|
if (sign == 1)
|
|
{
|
|
sibling->x = parent->x + (sibling->x - parent->x) * ratio;
|
|
}
|
|
else
|
|
{
|
|
sibling->x = parent->x + (sibling->x - (x + width) ) * ratio;
|
|
}
|
|
break;
|
|
case View::ViewWindow:
|
|
break;
|
|
}
|
|
if (sibling->child1 != nullptr)
|
|
walkTreeResize(sibling->child1, sign);
|
|
if (sibling->child2 != nullptr)
|
|
walkTreeResize(sibling->child2, sign);
|
|
}
|
|
|
|
bool View::walkTreeResizeDelta(View* v, float delta, bool check)
|
|
{
|
|
View *p = v;
|
|
int sign = -1;
|
|
float ratio;
|
|
double newSize;
|
|
|
|
if (v->child1 != nullptr)
|
|
{
|
|
if (!walkTreeResizeDelta(v->child1, delta, check))
|
|
return false;
|
|
}
|
|
|
|
if (v->child2 != nullptr)
|
|
{
|
|
if (!walkTreeResizeDelta(v->child2, delta, check))
|
|
return false;
|
|
}
|
|
|
|
while ( p != child1 && p != child2 && (p = p->parent) != nullptr ) ;
|
|
|
|
if (p == child1)
|
|
sign = 1;
|
|
|
|
switch (type)
|
|
{
|
|
case View::HorizontalSplit:
|
|
delta = -delta;
|
|
ratio = (p->height + sign * delta) / p->height;
|
|
newSize = v->height * ratio;
|
|
if (newSize <= .1)
|
|
return false;
|
|
if (check)
|
|
return true;
|
|
v->height = (float) newSize;
|
|
if (sign == 1)
|
|
{
|
|
v->y = p->y + (v->y - p->y) * ratio;
|
|
}
|
|
else
|
|
{
|
|
v->y = p->y + delta + (v->y - p->y) * ratio;
|
|
}
|
|
break;
|
|
|
|
case View::VerticalSplit:
|
|
ratio = (p->width + sign * delta) / p->width;
|
|
newSize = v->width * ratio;
|
|
if (newSize <= .1)
|
|
return false;
|
|
if (check)
|
|
return true;
|
|
v->width = (float) newSize;
|
|
if (sign == 1)
|
|
{
|
|
v->x = p->x + (v->x - p->x) * ratio;
|
|
}
|
|
else
|
|
{
|
|
v->x = p->x + delta + (v->x - p->x) * ratio;
|
|
}
|
|
break;
|
|
case View::ViewWindow:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Observer* View::getObserver() const
|
|
{
|
|
return observer;
|
|
}
|
|
|
|
void View::switchTo(int gWidth, int gHeight)
|
|
{
|
|
renderer->setRenderRegion(int(x * gWidth),
|
|
int(y * gHeight),
|
|
int(width * gWidth),
|
|
int(height * gHeight));
|
|
}
|
|
|
|
bool View::isSplittable(Type type) const
|
|
{
|
|
// If active view is too small, don't split it.
|
|
return (type == View::HorizontalSplit && height >= 0.2f) ||
|
|
(type == View::VerticalSplit && width >= 0.2f);
|
|
}
|
|
|
|
bool View::isRootView() const
|
|
{
|
|
return parent == nullptr;
|
|
}
|
|
|
|
void View::split(Type type, Observer *o, float splitPos, View **split, View **view)
|
|
{
|
|
float w1, h1, w2, h2, x1, y1;
|
|
w1 = w2 = width;
|
|
h1 = h2 = height;
|
|
x1 = x;
|
|
y1 = y;
|
|
if (type == View::VerticalSplit)
|
|
{
|
|
w1 *= splitPos;
|
|
w2 -= w1;
|
|
x1 += w1;
|
|
}
|
|
else
|
|
{
|
|
h1 *= splitPos;
|
|
h2 -= h1;
|
|
y1 += h1;
|
|
}
|
|
|
|
*split = new View(type,
|
|
renderer,
|
|
nullptr,
|
|
x, y, width, height);
|
|
(*split)->parent = parent;
|
|
if (parent != nullptr)
|
|
{
|
|
if (parent->child1 == this)
|
|
parent->child1 = *split;
|
|
else
|
|
parent->child2 = *split;
|
|
}
|
|
(*split)->child1 = this;
|
|
|
|
width = w1;
|
|
height = h1;
|
|
parent = *split;
|
|
|
|
*view = new View(View::ViewWindow,
|
|
renderer,
|
|
o,
|
|
x1, y1, w2, h2);
|
|
(*split)->child2 = *view;
|
|
(*view)->parent = *split;
|
|
(*view)->zoom = zoom;
|
|
}
|
|
|
|
View* View::remove(View* v)
|
|
{
|
|
int sign;
|
|
View *sibling;
|
|
if (v->parent->child1 == v)
|
|
{
|
|
sibling = v->parent->child2;
|
|
sign = -1;
|
|
}
|
|
else
|
|
{
|
|
sibling = v->parent->child1;
|
|
sign = 1;
|
|
}
|
|
sibling->parent = v->parent->parent;
|
|
if (v->parent->parent != nullptr)
|
|
{
|
|
if (v->parent->parent->child1 == v->parent)
|
|
v->parent->parent->child1 = sibling;
|
|
else
|
|
v->parent->parent->child2 = sibling;
|
|
}
|
|
v->walkTreeResize(sibling, sign);
|
|
delete(v->parent);
|
|
delete(v);
|
|
return sibling;
|
|
}
|
|
|
|
void View::reset()
|
|
{
|
|
x = 0.0f;
|
|
y = 0.0f;
|
|
width = 1.0f;
|
|
height = 1.0f;
|
|
parent = nullptr;
|
|
child1 = nullptr;
|
|
child2 = nullptr;
|
|
}
|
|
|
|
void View::drawBorder(int gWidth, int gHeight, const Color &color, float linewidth)
|
|
{
|
|
Rect r(x * gWidth, y * gHeight, width * gWidth - 1, height * gHeight - 1);
|
|
r.setColor(color);
|
|
r.setType(Rect::Type::BorderOnly);
|
|
r.setLineWidth(linewidth);
|
|
renderer->drawRectangle(r);
|
|
}
|