📄 viewport.cpp
字号:
/*
This file is part of SWAIN (http://sourceforge.net/projects/swain).
Copyright (C) 2006 Daniel Lindstr鰉 and Daniel Nilsson
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.
*/
#include "StdAfx.h"
#include "ViewPort.h"
ViewPort::ViewPort(HWND hwnd){
my_hwnd = hwnd;
if(!(screen = GetDC(hwnd))){
throw "could not get hDC";
}
createBackbuffer();
canvas = NULL;
zoom = 1;
pan.x = 0; pan.y = 0;
overzoom = 1.0;
pen_standard = CreatePen(PS_SOLID, 1, RGB(0,0,0));
SelectObject(backbuf, pen_standard);
}
ViewPort::~ViewPort(void){
destroyBackbuffer();
DeleteDC(screen);
}
void ViewPort::createBackbuffer(void) {
RECT rc;
if(!(backbuf = CreateCompatibleDC(screen))){
throw "could not create backbuffer";
}
GetClientRect(my_hwnd, &rc);
width = rc.right-rc.left;
height = rc.bottom-rc.top;
backbuf_bitmap = CreateCompatibleBitmap(screen, width, height);
SelectObject(backbuf, backbuf_bitmap);
SetStretchBltMode(backbuf, COLORONCOLOR);
}
void ViewPort::destroyBackbuffer(void) {
DeleteObject(backbuf_bitmap);
DeleteDC(backbuf);
}
void ViewPort::screenResized(void) {
destroyBackbuffer();
createBackbuffer();
setZoomPan(zoom, &pan);
redraw();
}
void ViewPort::flip(void){
BitBlt(screen, 0, 0, width, height, backbuf, 0, 0, SRCCOPY);
}
void ViewPort::flip(FRECT *frect){
int x = f2x(frect->left);
int y = f2y(frect->top);
int w = f2x(frect->right) - x + 1;
int h = f2y(frect->bottom) - y + 1;
BitBlt(screen, x, y, w, h, backbuf, x, y, SRCCOPY);
}
void ViewPort::clearRect(FRECT *rect) {
RECT rc;
rc.left = f2x(rect->left);
rc.top = f2y(rect->top);
rc.right = f2x(rect->right);
rc.bottom = f2y(rect->bottom);
FillRect(backbuf, &rc, (HBRUSH) GetStockObject(WHITE_BRUSH));
}
void ViewPort::drawPolyLine(FPOINT *points, int count){
this->drawPolyLine(points, count, RGB(0, 0, 0));
}
void ViewPort::drawPolyLine(FPOINT *points, int count, COLORREF color){
HPEN old, pen = CreatePen(PS_SOLID, 2, color);
POINT *p = new POINT[count];
for(int i=0; i<count; i++){
p[i].x = f2x(points[i].x);
p[i].y = f2y(points[i].y);
}
old = (HPEN)SelectObject(backbuf, pen);
Polyline(backbuf, p, count);
SelectObject(backbuf, old);
delete(p);
DeleteObject(pen);
}
void ViewPort::drawRectangle(float left, float top, float right, float bottom, COLORREF color, int style){
HPEN old, pen = CreatePen(style, 1, color);
old = (HPEN)SelectObject(backbuf, pen);
RECT rc;
rc.left = f2x(left);
rc.top = f2y(top);
rc.right = f2x(right);
rc.bottom = f2y(bottom);
DrawFocusRect(backbuf, &rc);
SelectObject(backbuf, old);
DeleteObject(pen);
}
void ViewPort::drawPolygon(FPOINT *points, int count){
POINT *p = new POINT[count];
for(int i=0; i<count; i++){
p[i].x = f2x(points[i].x);
p[i].y = f2y(points[i].y);
}
SelectObject(backbuf, pen_standard);
Polygon(backbuf, p, count);
delete(p);
}
void ViewPort::drawBitmap(Bitmap *bitmap, FRECT *dest, RECT *source){
HDC hdc = bitmap->getHDC();
StretchBlt(backbuf, f2x(dest->left), f2y(dest->top), f2x(dest->right)-f2x(dest->left),
f2y(dest->bottom)-f2y(dest->top),
bitmap->getHDC(), source->left, source->top, source->right-source->left, source->bottom-source->top, SRCCOPY);
}
void ViewPort::mouseDown(POINT *p){
FPOINT fp;
fp.x = x2f(p->x);
fp.y = y2f(p->y);
if(!canvas)
throw "no canvas availible";
this->canvas->mouseDown(&fp);
}
void ViewPort::mouseUp(POINT *p){
FPOINT fp;
fp.x = x2f(p->x);
fp.y = y2f(p->y);
if(!canvas)
throw "no canvas availible";
this->canvas->mouseUp(&fp);
}
void ViewPort::mouseDragged(POINT *p){
FPOINT fp;
fp.x = x2f(p->x);
fp.y = y2f(p->y);
if(!canvas)
throw "no canvas availible";
this->canvas->mouseDragged(&fp);
}
void ViewPort::redraw(void) {
RECT rc = { 0, 0, width, height };
redraw(&rc);
}
void ViewPort::redraw(RECT *rect){
FRECT frect;
frect.left = x2f(rect->left);
frect.top = y2f(rect->top);
frect.right = x2f(rect->right + 1);
frect.bottom = y2f(rect->bottom + 1);
HRGN rgn = CreateRectRgnIndirect(rect);
SelectClipRgn(backbuf, rgn);
canvas->redraw(&frect);
SelectClipRgn(backbuf, NULL);
DeleteObject(rgn);
}
void ViewPort::invalidate(FRECT *frect) {
RECT rect;
rect.left = f2x(frect->left);
rect.top = f2y(frect->top);
rect.right = f2x(frect->right);
rect.bottom = f2y(frect->bottom);
InvalidateRect(my_hwnd, &rect, FALSE);
}
void ViewPort::invalidate(void){
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = width;
rect.bottom = height;
InvalidateRect(my_hwnd, &rect, FALSE);
}
void ViewPort::alignRect(FRECT *frect) {
frect->left = x2f(f2x(frect->left));
frect->top = y2f(f2y(frect->top));
frect->right = x2f(f2x(frect->right) + 1);
frect->bottom = y2f(f2y(frect->bottom) + 1);
}
// Some GDI functions such as "polygon" draws outside the bounds by one pixel.
// This function adjusts a bounding rectangle to compensate for this.
void ViewPort::expandBoundsHack(FRECT *frect) {
frect->right += x2f(1) - x2f(0);
frect->bottom += y2f(1) - y2f(0);
frect->left -= x2f(1) - x2f(0);
frect->top -= y2f(1) - y2f(0);
}
float ViewPort::getMaxZoom(void) {
FRECT fext;
RECT ext;
canvas->getExtents(&fext, &ext);
float cw = fext.right - fext.left; // width of canvas in float coords
float ch = fext.bottom - fext.top; // height of canvas in float coords
int cpw = ext.right - ext.left;
int cph = ext.bottom - ext.top;
return overzoom * max (cpw / (ZOOMFACTOR * cw),
cph / (ZOOMFACTOR * ch));
}
float ViewPort::getMinZoom(void) {
FRECT fext;
canvas->getExtents(&fext, NULL);
float cw = fext.right - fext.left; // width of canvas in float coords
float ch = fext.bottom - fext.top; // height of canvas in float coords
return max((float)width / (ZOOMFACTOR * cw),
(float)height / (ZOOMFACTOR * ch));
}
void ViewPort::setZoomPan(float z, FPOINT *p){
// Adjust the zoom...
if (z > getMaxZoom()) {
z = getMaxZoom();
}
if (z < getMinZoom()) {
z = getMinZoom();
}
float vpw = P2F(z, 0, width); // width of viewport in float coords
float vph = P2F(z, 0, height); // height of viewport in float coords
FRECT fext;
canvas->getExtents(&fext, NULL);
// Don't pan outside canvas...
if(p->x < fext.left)
p->x = fext.left;
if(p->y < fext.top)
p->y = fext.top;
if((p->x + vpw) > fext.right)
p->x = fext.right - vpw;
if((p->y + vph) > fext.bottom)
p->y = fext.bottom - vph;
this->zoom = z;
this->pan.x = p->x;
this->pan.y = p->y;
this->invalidate();
}
float ViewPort::getZoom(void){
return zoom;
}
void ViewPort::getPan(FPOINT *p){
*p = pan;
}
void ViewPort::setOverzoom(float f) {
overzoom = f;
}
void ViewPort::drawDot(int x, int y){
DWORD color = RGB(255, 255, 255);
SetPixel(backbuf, x, y, color);
}
void ViewPort::setCanvas(Canvas *canvas){
this->canvas = canvas;
}
void ViewPort::getBounds(FRECT *rect){
rect->left = x2f(0);
rect->right = x2f(width);
rect->top = y2f(0);
rect->bottom = y2f(height);
}
void ViewPort::setBounds(FRECT *rect){
float zoom = (float)width/((rect->right - rect->left)*ZOOMFACTOR);
zoom += (float)height/((rect->bottom - rect->top)*ZOOMFACTOR);
zoom /= 2;
zoom = max(getMinZoom(), min(zoom, getMaxZoom()));
FPOINT offset;
offset.x = (rect->left + rect->right) / 2 - P2F(zoom, 0, width/2);
offset.y = (rect->top + rect->bottom) / 2 - P2F(zoom, 0, height/2);
this->setZoomPan(zoom, &offset);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -