📄 gwidgets.cpp
字号:
/* Copyright (C) 2006, Mike Gashler This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. see http://www.gnu.org/copyleft/lesser.html*/#include "GWidgets.h"#include "GImage.h"#include "GArray.h"#include "GDirList.h"#ifdef WIN32#include <direct.h>#else // WIN32#include <unistd.h>#endif // !WIN32#include "GFile.h"#include <math.h>GWidgetStyle::GWidgetStyle(){ m_nButtonFontSize = 14; m_nLabelFontSize = 14; m_fButtonFontWidth = (float).8; m_fLabelFontWidth = (float)1; m_cButtonTextColor = 0xff000000; m_cLabelTextColor = 0xff8888ff; m_cButtonPressedTextColor = gRGB(255, 255, 255); m_cTextBoxBorderColor = gRGB(255, 255, 255); m_cTextBoxTextColor = gRGB(255, 255, 255);}GWidgetStyle::~GWidgetStyle(){}void GWidgetStyle::DrawButtonText(GImage* pImage, int x, int y, int w, int h, GString* pString, bool pressed){ int nTempBufLen = pString->GetLength() + 1; GTEMPBUF(char, szText, nTempBufLen); pString->GetAnsi(szText); int nButtonFontSize = m_nButtonFontSize; if(h < nButtonFontSize) nButtonFontSize = h; int wid = pImage->MeasureHardTextWidth(nButtonFontSize, szText, m_fButtonFontWidth); GRect r; r.x = x + (w - wid) / 2; if(r.x < x) r.x = x; r.y = y + (h - nButtonFontSize) / 2; if(r.y < y) r.y = y; r.w = w - (r.x - x); r.h = nButtonFontSize; pImage->DrawHardText(&r, szText, pressed ? m_cButtonPressedTextColor : m_cButtonTextColor, m_fButtonFontWidth);}void GWidgetStyle::DrawLabelText(GImage* pImage, int x, int y, int w, int h, GString* pString, bool alignLeft, GColor c){ int nTempBufLen = pString->GetLength() + 1; GTEMPBUF(char, szText, nTempBufLen); pString->GetAnsi(szText); int nLabelFontSize = m_nLabelFontSize; if(h < nLabelFontSize) nLabelFontSize = h; int wid = pImage->MeasureHardTextWidth(nLabelFontSize, szText, m_fLabelFontWidth); GRect r; if(alignLeft) r.x = x; else { r.x = x + w - wid; if(r.x < x) r.x = x; } r.y = y + (h - nLabelFontSize) / 2; if(r.y < y) r.y = y; r.w = w - (r.x - x); r.h = nLabelFontSize; pImage->DrawHardText(&r, szText, c, m_fLabelFontWidth);}void GWidgetStyle::DrawHorizCurvedOutSurface(GImage* pImage, int x, int y, int w, int h){ if(w <= 0 || h <= 0) return; float fac = (float)1.1 / w; int n; for(n = 0; n < w; n++) { float t = (float)n * fac - (float).1; int shade = (int)(255 * (1 - (t * t))); pImage->DrawLine(x, y, x, y + h - 1, gRGB(shade, shade, 255)); x++; }}void GWidgetStyle::DrawHorizCurvedInSurface(GImage* pImage, int x, int y, int w, int h, int colorMaskRed, int colorMaskGreen, int colorMaskBlue){ if(w <= 0 || h <= 0) return; int n; for(n = 0; n < w; n++) { float t = (float)(n + n) / w - 1; int shade = (int)(64 + 191 * ((t * t))); pImage->DrawLine(x, y, x, y + h - 1, gRGB(colorMaskRed & shade, colorMaskGreen & shade, colorMaskBlue & shade)); x++; }}void GWidgetStyle::DrawVertCurvedOutSurface(GImage* pImage, int x, int y, int w, int h){ float fac = (float)1.1 / h; int yStart = 0; if(y < 0) yStart = -y; if(y + h > (int)pImage->GetHeight()) h = pImage->GetHeight() - y; int n; for(n = yStart; n < h; n++) { float t = (float)n * fac - (float).1; int shade = (int)(255 * (1 - (t * t))); pImage->DrawLine(x, y, x + w - 1, y, gRGB(shade, shade, 255)); y++; }}void GWidgetStyle::DrawVertCurvedInSurface(GImage* pImage, int x, int y, int w, int h){ int n; for(n = 0; n < h; n++) { float t = (float)(n + n) / h - 1; int shade = (int)(64 + 191 * ((t * t))); pImage->DrawLine(x, y, x + w - 1, y, gRGB(0, 0, shade)); y++; }}void GWidgetStyle::DrawCursor(GImage* pImage, int x, int y, int w, int h){ pImage->DrawBox(x, y, x + w, y + h, m_cTextBoxTextColor, false);}// ----------------------------------------------------------------------GWidget::GWidget(GWidgetGroup* pParent, int x, int y, int w, int h){ m_pParent = pParent; m_pStyle = pParent ? pParent->GetStyle() : NULL; m_rect.Set(x, y, w, h); if(pParent) pParent->AddWidget(this); else m_nID = -1; GAssert(m_nDebugCheck = 0x600df00d, "");}/*virtual*/ GWidget::~GWidget(){ GAssert(DebugCheck(), "corruption!"); //GAssert(m_pParent || GetType() == Dialog, "Unexpected root widget"); if(m_pParent) m_pParent->OnDestroyWidget(this);}#ifdef _DEBUGbool GWidget::DebugCheck(){ GAssert(m_nDebugCheck == 0x600df00d, "corruption!"); return true;}#endif // _DEBUGvoid GWidget::SetPos(int x, int y){ m_rect.x = x; m_rect.y = y; // todo: dirty the parent?}// ----------------------------------------------------------------------GWidgetAtomic::GWidgetAtomic(GWidgetGroup* pParent, int x, int y, int w, int h) : GWidget(pParent, x, y, w, h){}/*virtual*/ GWidgetAtomic::~GWidgetAtomic(){}void GWidgetAtomic::Draw(GWidgetGroupWithCanvas* pTarget){ GRect r, rTmp; GImage* pSrcImage = GetImage(&r); GImage* pCanvas; int x = m_rect.x; int y = m_rect.y; GWidgetGroup* pGroup; for(pGroup = this->GetParent(); pGroup; pGroup = pGroup->GetParent()) { pCanvas = pGroup->GetImage(&rTmp); if(pCanvas) pCanvas->AlphaBlit(x, y, pSrcImage, &r); if(pGroup == pTarget) break; x += pGroup->m_rect.x; y += pGroup->m_rect.y; }}/*virtual*/ void GWidgetAtomic::OnChar(char c){ if(m_pParent) m_pParent->OnChar(c);}/*virtual*/ void GWidgetAtomic::OnMouseMove(int dx, int dy){}// ----------------------------------------------------------------------GWidgetGroup::GWidgetGroup(GWidgetGroup* pParent, int x, int y, int w, int h) : GWidget(pParent, x, y, w, h){ m_pWidgets = new GPointerArray(16); m_dirty = true;}/*virtual*/ GWidgetGroup::~GWidgetGroup(){ GWidget* pWidget; while(m_pWidgets->GetSize() > 0) { pWidget = (GWidget*)m_pWidgets->GetPointer(0); delete(pWidget); } delete(m_pWidgets);}void GWidgetGroup::AddWidget(GWidget* pWidget){ m_pWidgets->AddPointer(pWidget); pWidget->m_nID = m_pWidgets->GetSize() - 1; m_dirty = true;}// todo: use a divide-and-conquer technique to improve performance/*virtual*/ GWidgetAtomic* GWidgetGroup::FindAtomicWidget(int x, int y){ int n; int nCount = m_pWidgets->GetSize(); GWidget* pWidget; for(n = 0; n < nCount; n++) { pWidget = (GWidget*)m_pWidgets->GetPointer(n); if(pWidget->GetRect()->DoesInclude(x, y)) { if(pWidget->IsAtomicWidget()) return (GWidgetAtomic*)pWidget; else { GRect* pRect = pWidget->GetRect(); return ((GWidgetGroup*)pWidget)->FindAtomicWidget(x - pRect->x, y - pRect->y); } } } return NULL;}int GWidgetGroup::GetChildWidgetCount(){ return m_pWidgets->GetSize();}GWidget* GWidgetGroup::GetChildWidget(int n){ return (GWidget*)m_pWidgets->GetPointer(n);}/*virtual*/ void GWidgetGroup::OnDestroyWidget(GWidget* pWidget){ if(pWidget->m_nID >= 0) { // Remove the widget from my list GAssert(GetChildWidget(pWidget->m_nID) == pWidget, "bad id"); int nLast = m_pWidgets->GetSize() - 1; GWidget* pLast = (GWidget*)m_pWidgets->GetPointer(nLast); pLast->m_nID = pWidget->m_nID; m_pWidgets->SetPointer(pWidget->m_nID, pLast); m_pWidgets->DeleteCell(nLast); pWidget->m_nID = -1; m_dirty = true; } if(m_pParent) m_pParent->OnDestroyWidget(pWidget);}// ----------------------------------------------------------------------GWidgetGroupWithCanvas::GWidgetGroupWithCanvas(GWidgetGroup* pParent, int x, int y, int w, int h) : GWidgetGroup(pParent, x, y, w, h){ m_image.SetSize(w, h);}/*virtual*/ GWidgetGroupWithCanvas::~GWidgetGroupWithCanvas(){}/*virtual*/ GImage* GWidgetGroupWithCanvas::GetImage(GRect* pOutRect){ if(m_dirty) Update(); pOutRect->x = 0; pOutRect->y = 0; pOutRect->w = m_image.GetWidth(); pOutRect->h = m_image.GetHeight(); return &m_image;}void GWidgetGroupWithCanvas::Draw(GWidgetGroupWithCanvas* pTarget){ GRect r, rTmp; GImage* pSrcImage = GetImage(&r); GImage* pCanvas; int x = m_rect.x; int y = m_rect.y; GWidgetGroup* pGroup; for(pGroup = this->GetParent(); pGroup; pGroup = pGroup->GetParent()) { pCanvas = pGroup->GetImage(&rTmp); if(pCanvas) pCanvas->Blit(x, y, pSrcImage, &r); if(pGroup == pTarget) break; x += pGroup->m_rect.x; y += pGroup->m_rect.y; }}// ----------------------------------------------------------------------GWidgetDialog::GWidgetDialog(int w, int h, GColor cBackground) : GWidgetGroupWithCanvas(NULL, 0, 0, w, h){ m_cBackground = cBackground; m_pStyle = new GWidgetStyle(); m_pGrabbedWidget = NULL; m_pFocusWidget = NULL; m_prevMouseX = 0; m_prevMouseY = 0;}/*virtual*/ GWidgetDialog::~GWidgetDialog(){ ReleaseWidget(); delete(m_pStyle);}/*virtual*/ void GWidgetDialog::Update(){ m_image.Clear(m_cBackground); m_dirty = false; int n; int nCount = m_pWidgets->GetSize(); GWidget* pWidget; for(n = 0; n < nCount; n++) { pWidget = (GWidget*)m_pWidgets->GetPointer(n); pWidget->Draw(this); }}void GWidgetDialog::SetFocusWidget(GWidgetAtomic* pWidget){ if(m_pFocusWidget != pWidget) { if(m_pFocusWidget) m_pFocusWidget->OnLoseFocus(); m_pFocusWidget = pWidget; if(pWidget) pWidget->OnGetFocus(); }}void GWidgetDialog::GrabWidget(GWidgetAtomic* pWidget, int mouseX, int mouseY){ ReleaseWidget(); m_pGrabbedWidget = pWidget; SetFocusWidget(pWidget); if(pWidget) { GWidget* pTmp; GRect* pRect; for(pTmp = pWidget; pTmp; pTmp = pTmp->GetParent()) { pRect = pTmp->GetRect(); mouseX -= pRect->x; mouseY -= pRect->y; } pWidget->Grab(mouseX, mouseY); }}void GWidgetDialog::ReleaseWidget(){ if(!m_pGrabbedWidget) return; // Use a local var in case the handler destroys this dialog GWidgetAtomic* pGrabbedWidget = m_pGrabbedWidget; m_pGrabbedWidget = NULL; pGrabbedWidget->Release();}/*virtual*/ void GWidgetDialog::OnDestroyWidget(GWidget* pWidget){ if(pWidget == m_pGrabbedWidget) m_pGrabbedWidget = NULL; if(pWidget == m_pFocusWidget) m_pFocusWidget = NULL; GWidgetGroup::OnDestroyWidget(pWidget);}void GWidgetDialog::HandleChar(char c){ if(!m_pFocusWidget) return; m_pFocusWidget->OnChar(c);}bool GWidgetDialog::HandleMousePos(int x, int y){ x -= m_prevMouseX; y -= m_prevMouseY; if(x == 0 && y == 0) return false; m_prevMouseX += x; m_prevMouseY += y; if(!m_pGrabbedWidget) return false; m_pGrabbedWidget->OnMouseMove(x, y); return true;}// ----------------------------------------------------------------------GWidgetTextButton::GWidgetTextButton(GWidgetGroup* pParent, int x, int y, int w, int h, GString* pText): GWidgetAtomic(pParent, x, y, w, h){ m_image.SetSize(w * 2, h); m_text.Copy(pText); m_pressed = false; m_dirty = true;}/*virtual*/ GWidgetTextButton::~GWidgetTextButton(){}/*virtual*/ void GWidgetTextButton::Grab(int x, int y){ m_pressed = true; Draw(NULL); m_pParent->OnPushTextButton(this);}/*virtual*/ void GWidgetTextButton::Release(){ m_pressed = false; Draw(NULL); m_pParent->OnReleaseTextButton(this);}void GWidgetTextButton::Update(){ m_dirty = false; // Draw the non-pressed image int w = m_image.GetWidth() / 2; int h = m_image.GetHeight(); m_pStyle->DrawVertCurvedOutSurface(&m_image, 0, 0, w, h); m_pStyle->DrawButtonText(&m_image, 0, 0, w, h, &m_text, false); m_image.DrawBox(0, 0, w - 1, h - 1, gRGB(64, 64, 64), false); // Draw the pressed image int nHorizOfs = (int)(w * (float).05); int nVertOfs = (int)(h * (float).15); m_pStyle->DrawVertCurvedInSurface(&m_image, w, 0, w, h); m_pStyle->DrawButtonText(&m_image, w + nHorizOfs, nVertOfs, w - nHorizOfs, h - nVertOfs, &m_text, true); m_image.DrawBox(w, 0, w + w - 1, h - 1, gRGB(255, 255, 255), false);}GImage* GWidgetTextButton::GetImage(GRect* pOutRect){ if(m_dirty) Update(); pOutRect->x = m_pressed ? m_image.GetWidth() / 2 : 0; pOutRect->y = 0; pOutRect->w = m_image.GetWidth() / 2; pOutRect->h = m_image.GetHeight(); return &m_image;}void GWidgetTextButton::SetSize(int w, int h){ m_rect.w = w; m_rect.h = h; m_image.SetSize(w * 2, h); m_dirty = true;}void GWidgetTextButton::SetText(GString* pText){ m_text.Copy(pText); m_dirty = true; Draw(NULL);}void GWidgetTextButton::SetText(const char* szText){ m_text.Copy(szText); m_dirty = true; Draw(NULL);}// ----------------------------------------------------------------------GWidgetImageButton::GWidgetImageButton(GWidgetGroup* pParent, int x, int y, GImage* pImage): GWidgetAtomic(pParent, x, y, pImage->GetWidth() / 2, pImage->GetHeight()){ m_image.CopyImage(pImage); m_pressed = false;}/*virtual*/ GWidgetImageButton::~GWidgetImageButton(){}/*virtual*/ void GWidgetImageButton::Grab(int x, int y){ m_pressed = true; Draw(NULL);}/*virtual*/ void GWidgetImageButton::Release(){ m_pressed = false; Draw(NULL); m_pParent->OnReleaseImageButton(this);}GImage* GWidgetImageButton::GetImage(GRect* pOutRect){ pOutRect->x = m_pressed ? m_image.GetWidth() / 2 : 0; pOutRect->y = 0; pOutRect->w = m_image.GetWidth() / 2; pOutRect->h = m_image.GetHeight(); return &m_image;}// ----------------------------------------------------------------------GWidgetAnimation::GWidgetAnimation(GWidgetGroup* pParent, int x, int y, GImage* pImage, int nFrames): GWidgetAtomic(pParent, x, y, pImage->GetWidth() / 2, pImage->GetHeight()){ m_image.CopyImage(pImage); m_nFrames = nFrames; m_nFrame = 0;}/*virtual*/ GWidgetAnimation::~GWidgetAnimation(){}/*virtual*/ void GWidgetAnimation::Grab(int x, int y){}/*virtual*/ void GWidgetAnimation::Release(){}GImage* GWidgetAnimation::GetImage(GRect* pOutRect){ int nFrameWidth = m_image.GetWidth() / m_nFrames; pOutRect->x = m_nFrame * nFrameWidth; pOutRect->y = 0; pOutRect->w = nFrameWidth; pOutRect->h = m_image.GetHeight(); return &m_image;}void GWidgetAnimation::SetFrame(int nFrame){ m_nFrame = nFrame; Draw(NULL);}// ----------------------------------------------------------------------GWidgetTextLabel::GWidgetTextLabel(GWidgetGroup* pParent, int x, int y, int w, int h, GString* pText, GColor c): GWidgetAtomic(pParent, x, y, w, h){ m_image.SetSize(w, h); m_text.Copy(pText); m_alignLeft = true; m_cForeground = c; m_cBackground = 0x00000000; // transparent m_dirty = true;}/*virtual*/ GWidgetTextLabel::~GWidgetTextLabel(){}/*virtual*/ void GWidgetTextLabel::Grab(int x, int y){ m_pParent->OnClickTextLabel(this);}/*virtual*/ void GWidgetTextLabel::Release(){}void GWidgetTextLabel::Update(){ m_dirty = false; m_image.Clear(m_cBackground); m_pStyle->DrawLabelText(&m_image, 0, 0, m_image.GetWidth(), m_image.GetHeight(), &m_text, m_alignLeft, m_cForeground);}GImage* GWidgetTextLabel::GetImage(GRect* pOutRect){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -