view anagram/vaclgui/vaclgui.cpp @ 21:1c9dac05d040

Add lint-style FALLTHROUGH annotations to fallthrough cases. (in the parse engine and thus the output code) Document this, because the old output causes warnings with gcc10.
author David A. Holland
date Mon, 13 Jun 2022 00:04:38 -0400
parents 13d2b8934445
children
line wrap: on
line source

/*
 * AnaGram, A System for Syntax Directed Programming
 * Copyright 1997-2002 Parsifal Software. All Rights Reserved.
 * See the file COPYING for license and usage terms.
 *
 * vaclgui.cpp
 */

//#include <iaccel.hpp>
#include <iapp.hpp>
#include <icoordsy.hpp>
#include <iexcept.hpp>
#include <ifont.hpp>
//#include <igroupbx.hpp>
#include <iiconctl.hpp>
//#include <iinfoa.hpp>
#include <imsgbox.hpp>
#include <ipainevt.hpp>
#include <ipainhdr.hpp>
//#include <iprofile.hpp>
#include <irefcnt.hpp>

#include "action.h"
#include "agcstack.h"
#include "aglib.h"
#include "agrect.hpp"
#include "agstring.h"
#include "assert.h"
#include "engdef.h"
#include "ctrlpanel.hpp"
#include "base.h"
#include "bpu.h"
#include "help.h"
#include "multiline.hpp"
#include "operations.h"
#include "textfile.h"
#include "sums-defs.h"
#include "vaclgui-res.h"
#include "vaclgui.hpp"
#include "version.h"

//#define INCLUDE_LOGGING
#include "log.h"


#define DLL


ActionWindow *pActionWindow = 0;

IPoint         cascadeIncrement;
IPoint         cascadeOffset(0,0);
IPoint         cascadeOrigin(0,0);
AgString       commandLineFile;
IPointerHandle iconHandle;
AgAction       idAction;
text_file      inputFile;
IFont          menuFont;
int            messageBoxShowing = 0;


// declared in base.h
int nextChildId(void) {
  //LOGSECTION("nextChildId");
  static int next = 0x1000;
  //LOGV(next);
  return next++;
}

void messageBeep() {
  LOGSECTION("messageBeep");
  MessageBeep(MB_ICONEXCLAMATION);
}

AgQuadrant findQuadrant(IWindow *w) {
  RECT r;
  SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  AgRectangle desktop(r);
  cint sz = desktop.size()/2;
  AgQuadrant quad = upperLeft;
  AgRectangle wRect(w);
  int i;
  int area[4] = {0, 0, 0, 0};
  for (i = 0; i < 4; i++) {
    AgQuadrant corner = (AgQuadrant) i;
    AgQuadrant quadrant = (AgQuadrant) (i^3);
    AgRectangle test(desktop.position(corner), sz, quadrant);
    area[i] = test.intersection(wRect).area();
    if (area[i] > area[quad]) {
      quad = (AgQuadrant) i;
    }
  }
  return quad;
}

static const struct {
  AgQuadrant corner, quadrant;
} placement[8] = {
  { lowerLeft,  lowerRight },
  { lowerRight, lowerLeft },
  { upperLeft,  upperRight },
  { upperRight, upperLeft },
  { upperRight, lowerRight },
  { lowerRight, upperRight },
  { upperLeft,  lowerLeft },
  { lowerLeft,  upperLeft }
};

static cint positionWindow(cint measure, LayoutRef reference, cint sz) {
  LOGSECTION("positionWindow");
  int i;
  int area[8];
  AgRectangle test[8];
  for (i = 0; i < 8; i++) {
    AgQuadrant corner   = placement[i].corner;
    AgQuadrant quadrant = placement[i].quadrant;
    LOGV(i) LCV(corner) LCV(quadrant);

    test[i] = AgRectangle(reference.position(corner), sz, quadrant);
    LOGV(reference.position(corner));
    LOGV(test[i].position());
    test[i].limit(measure);
    LOGV(test[i].position());
    area[i] = reference.overlap(test[i]);
    LOGV(test[i].position()) LCV(test[i].size()) LCV(area[i]);
  }
  int minArea = area[0];
  int optimalPlacement = 0;
  for (i = 1; i < 8; i++) {
    if (area[i] >= minArea) {
      continue;
    }
    minArea = area[i];
    optimalPlacement = i;
  }
  LOGV(minArea) LCV(optimalPlacement);
  return test[optimalPlacement].position(upperLeft);
}

IRectangle adjustPos(IRectangle &r) {
  RECT rd;
  SystemParametersInfo(SPI_GETWORKAREA, 0, &rd, 0);
  IRectangle desktop(rd.left, rd.top, rd.right, rd.bottom);
  ISize newSize = r.size().minimum(desktop.size());
  newSize = newSize.maximum(ISize(100, 100));
  r.sizeTo(newSize);
  IPoint where = r.maxXMaxY().minimum(desktop.maxXMaxY());
  where -= newSize;
  r.moveTo(where);
  where = r.minXMinY().maximum(IPoint(0, 0));
  r.moveTo(where);
  return r;
}

class Damaged : public AgFrame {
private:
  MultiLineText message;

public:
  Damaged(const char *failure);
  ~Damaged();
  void showme();
};

Damaged::Damaged(const char *failure)
  : AgFrame(IFrameWindow::border
            | dialogBackground
            | IFrameWindow::windowList
            | IFrameWindow::systemMenu)
  , message(this)
{
  LOGSECTION("Damaged");
  AgString f1 = "Initialization failure: ";
  AgString f2 = failure;
  AgString f3 = code_segment("broken");
  AgString msg = f1.concat(f2).concat("\n\v").concat(f3);
  LOGV(msg);
  message.setText(msg.pointer());
  IFont textFont = IFont("Arial", 9);
  message.setFont(textFont);
  int leading = textFont.maxSize().height() + textFont.externalLeading();
  LOGV(leading);
  message.setVTab(leading/2);
}

Damaged::~Damaged() {
  pActionWindow->close();
}

void Damaged::showme() {
  LOGSECTION("Damaged::show");
  ISize frameSize = frameRectFor(IRectangle(message.minimumSize())).size();
  LOGV(frameSize.asString());
  setClient(&message);
  sizeTo(frameSize);
  IPoint where = (IPair) place(IWindow::desktopWindow()->size(),
			       frameSize, 11);
  LOGV(where.asString());
  moveTo(where);
  show().setFocus();
}

class SplashTimer : public ITimerFn {
private:
  IFrameWindow *window;
  ITimer &timer;
  AgAction finish;

public:
  SplashTimer(IFrameWindow *, ITimer &);
  SplashTimer(IFrameWindow *, ITimer &, AgAction);
  void timerExpired(unsigned long timerId);
};

SplashTimer::SplashTimer(IFrameWindow *window_,
			 ITimer &timer_)
  : window(window_)
  , timer(timer_)
{}

SplashTimer::SplashTimer(IFrameWindow *window_,
			 ITimer &timer_,
			 AgAction f)
  : window(window_)
  , timer(timer_)
  , finish(f)
{}

void SplashTimer::timerExpired(unsigned long) {
  LOGSECTION("SplashTimer::timerExpired");
  timer.stop();
  window->close();
  LOGS("splash window closed");
  finish.performDeferred();
}

class ReleaseSplash
  : public IFrameWindow
  , public IPaintHandler
{
private:
  ISetCanvas canvas;
    ISetCanvas top;
      IIconControl myicon;
      IStaticText logo;
      ICanvas   balance;
    IStaticText progName;
    MultiLineText copyright;
    //IStaticText licenseBox;
    //MultiLineText licensee;
  static ITimer timer;

public:
  ReleaseSplash();
  ~ReleaseSplash();
  Boolean paintWindow(IPaintEvent &event);
  static void makeReleaseSplash();
};

ReleaseSplash::~ReleaseSplash() {
  IPaintHandler::stopHandlingEventsFor(&canvas);
  IPaintHandler::stopHandlingEventsFor(&top);
  IPaintHandler::stopHandlingEventsFor(&balance);
}

Boolean ReleaseSplash::paintWindow(IPaintEvent &event) {
  LOGSECTION("ReleaseSplash::paintWindow");
  LOGV(event.rect().asString());
  event.clearBackground(IGUIColor::dialogBgnd);
  return false;
}

ITimer ReleaseSplash::timer;

ReleaseSplash::ReleaseSplash()
  : IFrameWindow(nextChildId(),
                 AgFrame::frameParent,
                 AgFrame::frameOwner,
                 IRectangle(),
                 dialogBackground | dialogBorder)
  , canvas(nextChildId(),this, this, IRectangle(),
	     ISetCanvas::verticalDecks
	   | ISetCanvas::packTight
	   | ISetCanvas::centerAlign
	   | IWindow::clipChildren
	   | IWindow::visible)
  , top(nextChildId(), &canvas, &canvas, IRectangle(),
	  ISetCanvas::horizontalDecks
	| ISetCanvas::packTight
	| ISetCanvas::centerVerticalAlign
	| IWindow::clipChildren
	| IWindow::visible
      )
  , myicon(nextChildId(), &top, &top, iconHandle,IRectangle(),
	   IIconControl::classDefaultStyle | IIconControl::fillBackground)
  , logo(nextChildId(), &top, &top)
  , balance(nextChildId(), &top, &top)
  , progName(nextChildId(), &canvas, &canvas)
  , copyright(&canvas)
  //, licenseBox(nextChildId(), &canvas, &canvas)
  //, licensee(&canvas, IRectangle(),
  //             IStaticText::classDefaultStyle
  //           | IStaticText::border3D)
{
  IPaintHandler::handleEventsFor(&canvas);
  IPaintHandler::handleEventsFor(&top);
  IPaintHandler::handleEventsFor(&balance);
  //myicon.setBackgroundColor(IGUIColor::dialogBgnd);
  logo.setFont(IFont("Arial", 20));
  logo.font().setBold();
  logo.setText("AnaGram");
  IFont textFont("Arial",8);
  progName.setFont(IFont("Arial",12));
  progName.font().setBold();
  progName.setText(BASEVERSIONSTRING);
  copyright.setFont(IFont("Arial", 8));
  //
  // This used to have a literal iso-latin-1 copyright char in it.
  // However, I've been compelled to remove it, including even from
  // this comment, not because any compiler rejects it (though they
  // would technically be within their rights) but because Red Hat's
  // foolish and reckless default locale settings and/or Red Hat's
  // custom patch set seem to render Red Hat-based versions of Emacs
  // incapable of touching the file without mangling it.
  //
  // I am not terribly surprised to discover this. RH seems to do a
  // lot of work to make sure they can put the 'sux' in 'linsux'.
  //
  // (i18n is a fine thing, but it has to *work*, especially since
  // non-English speakers can't just shut it all off and do without.)
  //
  // Fortunately, the copyright character is not legally necessary.
  //
  copyright.setText("Copyright 1993-2002 Parsifal Software. "
		    "All Rights Reserved.\n"
		    "Copyright 2006, 2007 David A. Holland. "
		    "All Rights Reserved.\n"
		    "\n"
		    "This version of AnaGram is free software.\n"
		    "There is NO WARRANTY.\n"
		    "See \"license\" in the help system for details.\n");
  copyright.setMinimumSize(copyright.calcMinimumSize());

  //licenseBox.setFont(textFont);
  //licenseBox.setText("This copy of AnaGram is registered to:");

  //licensee.setFont(textFont);
  //licensee.setText(licenseeText().pointer());
  //LOGV(licenseBox.font().name()) LCV(licenseBox.font().pointSize());
  //LOGV(licensee.font().name()) LCV(licensee.font().pointSize());
  //int leading = textFont.maxSize().height() + textFont.externalLeading();
  //licensee.setMargin(leading, leading);
  //licensee.setVTab(leading/2);

  canvas.setDeckCount(1);
  top.setDeckCount(1);
  setClient(&canvas);
  //myicon.sizeTo(myicon.minimumSize());
  //balance.sizeTo(myicon.minimumSize());
  balance.setMinimumSize(myicon.minimumSize());
  //logo.sizeTo(logo.minimumSize());
  //top.sizeTo(top.minimumSize());
  //licenseBox.sizeTo(licenseBox.minimumSize());

  //ISize minSize = licenseBox.minimumSize();
  //ISize licenseeSize = licensee.calcMinimumSize();
  //if (licenseeSize.width() < minSize.width()) {
  //  licenseeSize.setWidth(minSize.width());
  //}
  //licensee.setMinimumSize(licenseeSize);

  ISize size = canvas.minimumSize();
  canvas.sizeTo(size);
  IRectangle r = frameRectFor(IRectangle(size));
  ISize windowSize = r.size();
  sizeTo(windowSize);
  ISize desktopSize = IWindow::desktopWindow()->size();
  ISize margin = (desktopSize - windowSize)/2;
  moveTo((IPoint) margin);
}

void ReleaseSplash::makeReleaseSplash() {
  LOGSECTION("Splash::makeReleaseSplash");
  ReleaseSplash *window = new ReleaseSplash;
  window->setAutoDeleteObject();
  window->show().refresh(IWindow::immediate);
#ifdef INCLUDE_LOGGING
  int posFlag =
#endif
    SetWindowPos(window->handle(),
		 HWND_TOPMOST,
		 0,0,0,0,
		 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
#ifdef INCLUDE_LOGGING
  if (posFlag == 0) {
    LOGV(GetLastError());
  }
#endif

  IReference<ITimerFn> timerFn(new SplashTimer(window, timer));
  window->timer.start(timerFn, 4000);
}

void bailOut(const char *problem) {
  LOGSECTION("bailOut");
  LOGV(problem);
  LOGSTACK;
  if (controlPanel->timer.isStarted()) {
    controlPanel->timer.stop();
  }
  IMessageBox messageBox(0);
  messageBox.setTitle("AnaGram");
  char msg[200];
  sprintf(msg, "%s\nUnexpected program termination", problem);
  messageBoxShowing++;
  messageBox.show(msg, IMessageBox::catastrophic);
  messageBoxShowing--;
  abort();
}

//void abortProgram() {
//  pActionWindow->close();
//}

static void setup() {
  LOGSECTION("setup");

  init_parser();

  const char *failure = checksums_ok();
  LOGS("checksums_ok call returned");
  LOGV(failure);

  if (failure) {
    Damaged *failwindow = new Damaged(failure);
    failwindow->setAutoDeleteObject();

    idAction = actionObject(failwindow, Damaged::showme);
  }
  else {
    idAction = actionObject(ControlPanel::makeControlPanel);
  }

  idAction.performDeferred();
}

void agGui(char *f) {
  LOGSECTION("agGui");
  LOGV((void *) agGui);

  AgString file(f);
  try {
    commandLineFile = file;
    LOGV(commandLineFile);
    ICoordinateSystem::setApplicationOrientation(
      ICoordinateSystem::originUpperLeft);

    iconHandle = IResourceLibrary().loadIcon(IDI_ICON, 0);
    ActionWindow actionWindow;
    pActionWindow = &actionWindow;
    AgAction::startup();
    AgFrame::frameOwner = pActionWindow;
    AgFrame::frameParent = IWindow::desktopWindow();
    engdef_init();
    help_init();
    defer(ReleaseSplash::makeReleaseSplash);
    defer(setup);

    LOGS("Starting program");
    IApplication::current().run();
    LOGS("Program complete");
  }
  catch(IException & IFLOG(ie)) {
    AgFrame::windowRegistry.clearActive();
    LOGSECTION_ON("catch(IException)");
    LOGSTACK;
    LOGEXCEPTION(ie);
    LOGS("Returned from logging exception");
    assert(0);
/*
    IMessageBox messageBox(0);
    LOGS("Created message box");
    messageBox.setTitle("AnaGram");
    LOGS("title set");
    messageBox.show(
      "AnaGram: Unexpected program termination",
      IMessageBox::catastrophic);
    LOGS("Returned from showing message");
*/
  }
  catch(Problem p) {
    AgFrame::windowRegistry.clearActive();
    LOGSECTION("catch(Problem)");
    LOGV(p.msg);
    LOGSTACK;
    assert(0);
/*
    IMessageBox messageBox(0);
    messageBox.setTitle("AnaGram");
    char msg[200];
    sprintf(msg, "Unexpected program termination\n%s", p.msg);
    messageBoxShowing++;
    messageBox.show(msg, IMessageBox::catastrophic);
    messageBoxShowing--;
*/
  }
  catch(...) {
    AgFrame::windowRegistry.clearActive();
    LOGSECTION_ON("catch(...)");
    LOGSTACK;
    assert(0);
/*
    IMessageBox messageBox(0);
    messageBox.setTitle("AnaGram...");
    messageBoxShowing++;
    messageBox.show(
      "AnaGram: Unexpected program termination",
      IMessageBox::catastrophic);
    messageBoxShowing--;
*/
  }
}

#if 0 /* was: ifndef DLL */

/**************************************************************/
/* historic main() program entry point                        */
/**************************************************************/
int main(int argc, char *argv[]) {
  init(argv[0]);

  int buildSwitch = 0;
  int i;
  AgString file;
  for (i = 1; i < argc; i++) {
    switch (argv[i][0]) {
      case '/':
      case '-':
        switch (argv[i][1]) {
          case 'b':
          case 'B':
            buildSwitch = 1;
            LOGS("set buildSwitch");
            break;
        }
        break;
      default:
	file = argv[i];
	break;
    }
  }
  if (buildSwitch) {
    return commandLineBuild(file.pointer());
  }
  agGui(file.pointer());
  return 0;
}

#endif /* 0 */

IPoint placeOnDesktop(ISize s, int ij) {
  RECT r;
  SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  ISize desktopSize(r.right - r.left, r.bottom - r.top);
  return (IPair) place(desktopSize, s, ij);
}

IPoint placeRelative(ISize s, IWindow *window) {
  RECT r;
  SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  ISize desktopSize(r.right - r.left, r.bottom - r.top);

  AgRectangle ref(window->position(), window->size());
  return (IPair) positionWindow(desktopSize, ref, s);
}

IPoint placeWindow(ISize s, LayoutRef ref) {
  RECT r;
  SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  ISize desktopSize(r.right - r.left, r.bottom - r.top);
  return (IPair) positionWindow(desktopSize, ref, s);
}