// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I // surface class #include #include #include #include #include #include // constructor windows31::windows31(popup* p, boolean autoupdate) : canvas(*p), _autoupdate(autoupdate) { *_print_device = 0; *_print_driver = 0; *_print_port = 0; cwp = p; heap_check(gfp = new grey_font_windows(0, 0)); curx = 0; cury = 0; canvas.bitblt(0, 0, canvas.width(), canvas.height(), NULL, 0, 0, BLACKNESS); canvas.update(); // these aren't used; initialise to assist debugging x_ofs = 0; y_ofs = 0; use_left = 0; use_right = 0; use_top = 0; use_bottom = 0; _dotsize = 1; // initialise the printer information (from Petzold) char pPrintInfo[80]; GetProfileString("windows", "device", ",,,", pPrintInfo, 80); strcpy(_print_device, strtok(pPrintInfo, ",")); strcpy(_print_driver, strtok(NULL, ", ")); strcpy(_print_port, strtok(NULL, ", ")); } // windows31 << LINE surface& windows31::operator<<(LINE& rhs) { static TPen pen(RGB(255, 255, 255)); canvas.set_pen(pen).moveto(rhs.x1(), rhs.y1()).lineto(rhs.x2(), rhs.y2()); if (_autoupdate) then canvas.update(); return *this; } // windows31 << dot surface& windows31::operator<<(dot& rhs) { const int ds = ( (rhs.size() == -1) ? _dotsize : rhs.size()); for (int n = 0; n < ds; n++) for (int m = 0; m < ds; m++) canvas.setpixel(rhs.x() - n, rhs.y() - m); if (_autoupdate) then canvas.update(); return *this; } // windows31 << text surface& windows31::operator<<(text& rhs) { if (!(rhs.length())) then return *this; canvas.fgc().bgc(); const char* cp = (const char*)rhs.words(); const int text_width = canvas.text_width(cp); int x = rhs.x(), y = rhs.y() - canvas.text_height(cp); if (x < 0) then x = image_left() + (int)((abs(x) / 100.0) * image_width()) - text_width / 2; canvas.write(cp, x, y); if (_autoupdate) then canvas.update(); // temporarily force an update // canvas.update(); return *this; } // move the current point void windows31::moveto(const int x, const int y) { curx = x; cury = y; } void windows31::flush(void) { if (!(gfp->null())) then { const int orig_y = cury; /* static */ TMemoryDC mem_dc; // try static to see if faster for (int n = 0; n < gfp->length(); n++) { if (!(gfp->null(n))) then { TBitmap& bm = *(TBitmap*)(gfp->memory_pattern(gfp->element(n))); mem_dc.SelectObject(bm); canvas.bitblt(curx, cury, gfp->width(), gfp->height(), mem_dc, 0, 0, SRCCOPY); } cury += gfp->height(); } canvas.update(curx, orig_y, gfp->width(), gfp->height() * gfp->length()); } gfp->length(0); } void windows31::clear(void) { gfp->length(0); canvas.clear().update(); } // invert (on screen only) void windows31::invert(void) { //TWindowDC(*cwp).BitBlt(0, 0, width(), height(), NULL, 0, 0, DSTINVERT); canvas.invert(); } // I cannot get this to work in OWL /* void windows31::print(const char*) { canvas.print(); } */ // print to the current printer void windows31::print(const char*) { // much of this routine needs to be rewritten and incorporated in a windows31_printer // object, so as to hide the details from higher level code // get the correct DLL char driver_file [13]; strcpy(driver_file, _print_driver); strcat(driver_file, ".DRV"); HINSTANCE hDriver = LoadLibrary(driver_file); if ((UINT)hDriver < 22) then fatal_error("Unable to load printer driver"); // the type LPFNDEVMODE seems to be utterly undocumented. According to the // examples in the SDK, a simple FARPROC should be sufficient. It is not. LPFNDEVMODE lpfnExtDeviceMode = (LPFNDEVMODE)GetProcAddress(hDriver, "ExtDeviceMode"); if (!lpfnExtDeviceMode) then // not windows 3.1 driver fatal_error("Device driver is not 3.1"); // take the easy way out // how large is the devmode for this printer? const int struct_size = (*lpfnExtDeviceMode)(cwp->HWindow, hDriver, NULL, _print_device, _print_port, NULL, NULL, 0); byte* device_mode_b = new byte [struct_size]; DEVMODE*& device_mode = (DEVMODE*)device_mode_b; // get the capabilities (*lpfnExtDeviceMode)(cwp->HWindow, hDriver, (DEVMODE*)device_mode_b, _print_device, _print_port, NULL, NULL, DM_COPY); // set it to landscape device_mode->dmOrientation = DMORIENT_LANDSCAPE; (*lpfnExtDeviceMode)(cwp->HWindow, hDriver, (DEVMODE*)device_mode_b, _print_device, _print_port, (DEVMODE*)device_mode_b, NULL, DM_MODIFY | DM_COPY); HDC hdcprint = CreateDC(_print_driver, _print_device, _print_port, device_mode_b); DOCINFO DocInfo; DocInfo.lpszDocName = "WMIDAS 17.00"; DocInfo.lpszOutput = NULL; StartDoc(hdcprint, &DocInfo); StartPage(hdcprint); int x_dpi = device_mode->dmPrintQuality, y_dpi = (device_mode->dmFields & DM_YRESOLUTION) ? device_mode->dmYResolution : x_dpi; // we have to make some guesses if the driver merely specifies a crude resolution switch (x_dpi) { case 0 : x_dpi = 300; break; // argh! The PS driver is messed up case DMRES_HIGH : x_dpi = 200; break; case DMRES_MEDIUM : x_dpi = 150; break; case DMRES_LOW : x_dpi = 100; break; case DMRES_DRAFT : x_dpi = 75; break; default : break; } switch (y_dpi) { case 0 : y_dpi = 300; break; case DMRES_HIGH : y_dpi = 200; break; case DMRES_MEDIUM : y_dpi = 150; break; case DMRES_LOW : y_dpi = 100; break; case DMRES_DRAFT : y_dpi = 75; break; default : break; } // we also fudge things if we are using the PCL driver and it says 150dpi (which usually // means a low-memory PCL printer) if (!strcmp(_print_driver, "HPPCL")) then { x_dpi = 300; y_dpi = 300; } const float x_size = 8.5, y_size = 11; // calculate the factor to scale the bitmap const int x_factor = (int)((x_dpi * x_size) / canvas.height()), y_factor = (int)((y_dpi * y_size) / canvas.width()), factor = MIN(x_factor, y_factor); // calculate the offset to place it nicely on the page const int x_offset = ((int)(x_dpi * x_size) - canvas.height() * factor) / 2, y_offset = ((int)(y_dpi * y_size) - canvas.width() * factor) / 2; // now copy the source bitmap into the destination hdc StretchBlt(hdcprint, x_offset, y_offset, canvas.width() * factor, canvas.height() * factor, canvas._memdc, 0, 0, canvas.width(), canvas.height(), SRCINVERT); EndPage(hdcprint); EndDoc(hdcprint); destroy_array(device_mode_b); DeleteDC(hdcprint); FreeLibrary(hDriver); }