Click here to Skip to main content
15,896,278 members
Articles / Desktop Programming / Win32

DWinLib - The Guts

Rate me:
Please Sign up or sign in to vote.
4.96/5 (8 votes)
17 Jan 2021CPOL28 min read 19.1K   374   15  
A little about how things work behind the scenes in DWinLib!
In this article, you will get an overview of the internal workings of DWinLib, a semi-simple wrapper for the Windows API.
// --------------------------------------------------------------------------------------- //
// AppWindow example implementation for a blank window, to show the fundaentals of         //
// programing a blank DWinLib window.                                                      //
// --------------------------------------------------------------------------------------- //

#include "PrecompiledHeaders.h"
#pragma hdrstop

#include "AppWindow.h"
#include "Application.h"
#include "DwlMdiManager.h"
#include "DwlScrollbar.h"
#include "DwlIniFile.h"
#include "HelpFileConstants.h"
#include "WinMainO.h"
extern WinMainO * gWinMain;
#include "UIManager.h"
#include "Globals.h"
extern Globals gGlobals;


namespace {
   wString winCaption = _T("Main Application Window");
   wString winClassName = _T("DockerWindow");
   int timeBoxHeight = 80;
   }


AppWindow::AppWindow(DwlControl * parent, int x, int y, int width, int height, bool openingFile) :
            DwlMdiBaseWin(parent, x, y, width, height),
            verScrollAmtC(0),
            horScrollAmtC(0),
            scrollbarWidthC(15),
            mouseSquareC(NULL) {

   appC.reset(new Application(this, openingFile));
   horScrollC.reset(new DwlScrollbar(this, DwlScrollbar::Horizontal, 0,
               clientHeight()-gGlobals.uiMan().scrollbarWidth(), clientWidth(),
               gGlobals.uiMan().scrollbarWidth()));
   verScrollC.reset(new DwlScrollbar(this, DwlScrollbar::Vertical,
               clientWidth()-gGlobals.uiMan().scrollbarWidth(), 0, 
               gGlobals.uiMan().scrollbarWidth(), clientHeight()));
   horScrollC->showWindow(true);
   verScrollC->showWindow(true);
   
   
   int ch = clientHeight();
   int cw = clientWidth();
   int sbw = gGlobals.uiMan().scrollbarWidth();
   horScrollC->moveWindow(0, ch-sbw, cw-sbw, sbw);
   verScrollC->moveWindow(cw-sbw, 0, sbw, ch-sbw);

   if (!openingFile) {
      //Do whatever is needed:
      }
   else {
      //Do whatever else is needed:
      }
   wHelpTopicC = HFC::AppWindow;
   updateScrolls();
   }


AppWindow::~AppWindow() {
   gWinMain->winMdiManager()->removeWindow(this);
   }


wString AppWindow::shortName() {
   return appC->shortName();
   }


wString AppWindow::fullName() {
   return appC->fullName();
   }


bool AppWindow::canClose() {
   return appC->canClose();
   }


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//                      BEGINNING OF ROUTINES COMMON TO DWINLIB APPWINDOWS
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
LRESULT AppWindow::wClose() {
   if (!appC->canClose()) return 0;
   LRESULT ret = DefMDIChildProc(hwndC, WM_CLOSE, 0, 0);
   delete this;
   gWinMain->updateUI();
   return ret;
   }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//                          END OF ROUTINES COMMON TO DWINLIB APPWINDOWS
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *


LRESULT AppWindow::wPosChanged(WINDOWPOS * p) {
   updateScrolls();
   RECT r;
   r.top = 0;
   r.left = 0;
   r.right = clientWidth() - (verScrollC->visible() ? verScrollC->width() : 0);
   r.bottom = clientHeight() - (horScrollC->visible() ? horScrollC->height() : 0);
   InvalidateRect(hwndC, &r, TRUE);
   UpdateWindow(hwndC);

  return DefMDIChildProc(hwndC, WM_WINDOWPOSCHANGED, 0, (LPARAM) p);
   }


LRESULT AppWindow::wPosChanging(WINDOWPOS * wp) {
   if (wp->cy < 100) wp->cy = 100;
   return DefMDIChildProc(hwndC, WM_WINDOWPOSCHANGING, 0, (LPARAM) wp);
   }


LRESULT AppWindow::wPaint(DwlDC & dc) {
   //Double-buffer for cleanliness.  Could be improved by holding a bitmap in memory at all
   //times, but as this is a non-critical sample application, we will save ourselves the
   //time.
   DwlDC mDC(dc); //Memory DC
   //Figure out how big our bitmap needs to be...
   int bmpWidth = horScrollAmtC+clientWidth();
   if (bmpWidth<SLW) bmpWidth = SLW;

   int bmpHeight = clientHeight() + verScrollAmtC;
   if (bmpHeight<SLW) bmpHeight = SLW;

   HBITMAP buffBitmap = CreateCompatibleBitmap(dc(), bmpWidth, bmpHeight);
   //The previous bitmap cannot be created by 'CreateCompatibleBitmap(mDC()...)'
   //The output becomes dithered in a bad way...

   mDC.bitmap(buffBitmap, true);
   RECT r1 = { 0, 0, bmpWidth, bmpHeight };
   HBRUSH brush = (HBRUSH)GetStockObject(GRAY_BRUSH);
   FillRect(mDC(), &r1, brush);

   RECT r2 = { 0, 0, SLW, SLW };
   brush = (HBRUSH)GetStockObject(WHITE_BRUSH);
   FillRect(mDC(), &r2, brush);

   std::vector<StupidSquare> & squares = appC->squares();
   size_t num = squares.size();
   for (size_t i=0; i<num; ++i) {
      if (!squares[i].selected() && !squares[i].hidden()) squares[i].blit(mDC);
      }

   if (mouseSquareC) blitSelectedSquare(mDC);

   if (needToBlitCornerC) {
      r1.left = clientWidth()-scrollbarWidthC+horScrollAmtC;
      r1.top  = clientHeight()-scrollbarWidthC+verScrollAmtC;
      r1.bottom = clientHeight()+verScrollAmtC;
      r1.right = clientWidth()+horScrollAmtC;
      brush = (HBRUSH)GetStockObject(GRAY_BRUSH);
      FillRect(mDC(), &r1, brush);
      }

   BitBlt(dc(), -horScrollAmtC, -verScrollAmtC, bmpWidth, bmpHeight, mDC(), 0, 0, SRCCOPY);
   return 0;
   }


void AppWindow::blitSelectedSquare(DwlDC & dc) {
   if (!mouseSquareC) return;
   mouseSquareC->blitSelected(dc, mousePointC.x-pointInSquareC.x,
               mousePointC.y-pointInSquareC.y);
   }


void AppWindow::updateDataAndViews() {
   //Do whatever is needed to get the views to update themselves
   updateScrolls();
   RECT r;
   r.top = 0;
   r.left = 0;
   r.right = clientWidth() - (verScrollC->visible() ? verScrollC->width() : 0);
   r.bottom = clientHeight() - (horScrollC->visible() ? horScrollC->height() : 0);
   InvalidateRect(hwndC, &r, TRUE);
   }


void AppWindow::updateScrolls() {
   needToBlitCornerC = false;
   verScrollC->showWindow(false);
   horScrollC->showWindow(false);
   int w = clientWidth();
   int h = clientHeight();
   //Determine which scrollbars need to be visible
   bool showBottomScroll(w<SLW+horScrollAmtC ? true : false);
   bool showRightScroll(h<SLW+verScrollAmtC ? true : false);
   if (showBottomScroll && !showRightScroll && h<SLW+scrollbarWidthC)
               showRightScroll = true;
   if (showRightScroll && !showBottomScroll && w<SLW+scrollbarWidthC)
               showBottomScroll = true;
               
   //Now, change the 'horScrollAmtC' and 'verScrollAmtC' variables, if the user's action is
   //attempting to uncover real estate below or beside the output 'square', and there is
   //real estate above or to the left of the window that is 'covered up'.
   int scrollbarWidth(showRightScroll ? scrollbarWidthC : 0);
   if (showBottomScroll && clientWidth()+horScrollAmtC-scrollbarWidth > SLW)
               horScrollAmtC = SLW-clientWidth()+scrollbarWidth;
   scrollbarWidth = showBottomScroll ? scrollbarWidthC : 0;
   if (showRightScroll && clientHeight() + verScrollAmtC-scrollbarWidth > SLW)
               verScrollAmtC = SLW-clientHeight()+scrollbarWidth;

   //Finally, show the appropriate scroll bars.
   if (showRightScroll && showBottomScroll) {
      horScrollC->showWindow(true);
      verScrollC->showWindow(true);
      verScrollC->moveWindow(w-scrollbarWidthC, 0, scrollbarWidthC, h-scrollbarWidthC);
      verScrollC->scrollTicksTotal(SLW);
      verScrollC->pageSize(clientHeight()-scrollbarWidthC);
      verScrollC->pos(verScrollAmtC);
      horScrollC->moveWindow(0, h-scrollbarWidthC, w-scrollbarWidthC, scrollbarWidthC);
      horScrollC->scrollTicksTotal(SLW);
      horScrollC->pageSize(clientWidth()-scrollbarWidthC);
      horScrollC->pos(horScrollAmtC);
      needToBlitCornerC = true;
      }
   else if (showRightScroll) {
      verScrollC->showWindow(true);
      verScrollC->moveWindow(w-scrollbarWidthC, 0, scrollbarWidthC, h);
      verScrollC->scrollTicksTotal(SLW);
      verScrollC->pageSize(clientHeight());
      verScrollC->pos(verScrollAmtC);
      horScrollAmtC = 0;
      }
   else if (showBottomScroll) {
      horScrollC->showWindow(true);
      horScrollC->moveWindow(0, h-scrollbarWidthC, w, scrollbarWidthC);
      horScrollC->scrollTicksTotal(SLW);
      horScrollC->pageSize(clientWidth());
      horScrollC->pos(horScrollAmtC);
      verScrollAmtC = 0;
      }
   else {
      horScrollAmtC = verScrollAmtC = 0;
      }
   }


LRESULT AppWindow::wScrollHor(WORD scrollCode, int pos, HWND ) {  // scrollHwnd
   //This is our response to Windows calling us, and simply calls INTO the scrollbar code.
   horScrollC->scroll(scrollCode, pos);
   return 0;
   }


LRESULT AppWindow::wScrollVer(WORD scrollCode, int pos, HWND ) { // scrollHwnd
   //This is our response to Windows calling us, and simply calls INTO the scrollbar code.
   verScrollC->scroll(scrollCode, pos);
   return 0;
   }


void AppWindow::scrollPosChanged(DwlScrollbar * bar, int pos) {
   //this is called FROM the scrollbar code, and is used to modify stuff on the window...
   if (bar == verScrollC.get()) {
      verScrollAmtC = pos;
      }
   else if (bar == horScrollC.get()) {
      horScrollAmtC = pos;
      }
   RECT r;
   r.top = 0;
   r.left = 0;
   r.right = clientWidth() - (verScrollC->visible() ? verScrollC->width() : 0);
   r.bottom = clientHeight() - (horScrollC->visible() ? horScrollC->height() : 0);
   InvalidateRect(hwndC, &r, TRUE);
   }


LRESULT AppWindow::wMouseDown(Button , WPARAM , SHORT x, SHORT y) {  //button flags
   //First, determine if the mouse is over a square:
   mouseSquareC = NULL;
   int numSquares = appC->numSquares();
   for (int i=0; i<numSquares; ++i) {
      mouseSquareC = appC->squares()[i].touch(x+horScrollAmtC, y+verScrollAmtC);
      if (mouseSquareC) break;
      }
   if (!mouseSquareC) return 0;
   SetCapture(hwndC);
   mouseSquareC->selected(true);
   appC->lastSquare(mouseSquareC);
   pointInSquareC.x = x+horScrollAmtC-mouseSquareC->x();
   pointInSquareC.y = y+verScrollAmtC-mouseSquareC->y();
   mousePointC.x = x+horScrollAmtC;
   mousePointC.y = y+verScrollAmtC;
   return 0;
   }


LRESULT AppWindow::wMouseMove(WPARAM , SHORT x, SHORT y) {   // keys
   if (!mouseSquareC) return 0;
   mousePointC.x = x+horScrollAmtC;
   mousePointC.y = y+verScrollAmtC;

   constrainSquare(mousePointC.x, mousePointC.y);

   //Check for touching other squares, and take appropriate action
   int numSquares = appC->numSquares();
   for (int i=0; i<numSquares; ++i) {
      StupidSquare * square = &appC->squares()[i];
      if (square == mouseSquareC) continue;
      if (square->hidden()) continue;
      if (square->touch(mousePointC.x-pointInSquareC.x, mousePointC.y-pointInSquareC.y)) {
         square->hidden(true);
         appC->hideUndoer()->hideSquares(mouseSquareC, square);
         ReleaseCapture();
         mouseSquareC->selected(false);
         appC->lastSquare(NULL);
         mouseSquareC = NULL;
         if (appC->gameOver()) MessageBox(gWinMain->hwnd(), TEXT("Game Over"),
                     TEXT("Stupid Squares"), MB_OK | MB_APPLMODAL);
         return 0;
         }
      }

   RECT r;
   r.top = 0;
   r.left = 0;
   r.right = clientWidth() - (verScrollC->visible() ? verScrollC->width() : 0);
   r.bottom = clientHeight() - (horScrollC->visible() ? horScrollC->height() : 0);
   InvalidateRect(hwndC, &r, TRUE);
   return 0;
   }


LRESULT AppWindow::wMouseUp(Button , WPARAM , SHORT x, SHORT y) {   //button flags
   if (!mouseSquareC) return 0;

   mousePointC.x = x+horScrollAmtC;
   mousePointC.y = y+verScrollAmtC;
   constrainSquare(mousePointC.x, mousePointC.y);

   ReleaseCapture();
   appC->moveUndoer()->moveSquare(mouseSquareC, mousePointC.x-pointInSquareC.x,
               mousePointC.y-pointInSquareC.y);
   mouseSquareC = NULL;
   return 0;
   }


void AppWindow::constrainSquare(LONG & mousePointX, LONG & mousePointY) {
   //mousePointX & Y are sent to this routine in ABSOLUTE coordinates, from top-left of
   //bitmap.  They are NOT screen coordinates at this point.  (IE - if the window has been
   //scrolled to the right 50 pixels, the 0,0 screen point will correspond to 50,0.)
   //The following will constrain the square to being within the visible screen, and not
   //going outside of the 700x700 or whatever max screen size (SLW) has been set to.
   if (mousePointX-pointInSquareC.x<horScrollAmtC)
      mousePointX = horScrollAmtC + pointInSquareC.x;
   else if
      (mousePointX > horScrollAmtC + clientWidth() - mouseSquareC->width() -
            (verScrollC->visible() ? scrollbarWidthC : 0) + pointInSquareC.x)

         mousePointX = horScrollAmtC + clientWidth() - mouseSquareC->width() -
            (verScrollC->visible() ? scrollbarWidthC : 0) + pointInSquareC.x;

   if (mousePointY-pointInSquareC.y<verScrollAmtC)
               mousePointY = verScrollAmtC + pointInSquareC.y;
   else if
      (mousePointY > verScrollAmtC + clientHeight() - mouseSquareC->width() -
                  (horScrollC->visible() ? scrollbarWidthC : 0) + pointInSquareC.y)

         mousePointY = verScrollAmtC + clientHeight() - mouseSquareC->width() -
                  (horScrollC->visible() ? scrollbarWidthC : 0) + pointInSquareC.y;

   if (mousePointX + mouseSquareC->width() > SLW)
               mousePointX = SLW - mouseSquareC->width()+pointInSquareC.x;
   if (mousePointY + mouseSquareC->width() > SLW)
               mousePointY = SLW - mouseSquareC->width()+pointInSquareC.y;
   }

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer www.randommonkeyworks.com
United States United States
I am the author of Laughing at the Devil: One Man’s Religious Discoveries. If you want to understand the astronomic investigations of our priests 3,000 years ago, LATD is the book to turn to. It opens up the thoughts that pushed them away from their earlier polytheism and towards our current definition of God.

Trained as a mechanical engineer, I have been involved with design, supervision, and project management. I taught myself C++ programming in order to play around with binaural beats more easily. I've also created various databases to help with project management and personal tasks.

Databases are cool and extremely useful! Happy coding, everybody!

Comments and Discussions