#include #include #include #include #include #include #include #include #include #include #include #include HIDDEN TPrinter* _printer = NULL; /////////////////////////////////////////////////////////// // Maschera impostazione stampante (fatta come si deve dopo 10 anni!) /////////////////////////////////////////////////////////// class TPrinter_setup_mask : public TAutomask { private: bool _skip_events; TString _pdev, _font; PRINT_RCD* _pcd; int _pcd_size; protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); void fill_font_list(); void fill_size_list(); public: void set_print_rcd(PRINT_RCD* pcd, int size); PRINT_RCD* get_print_rcd(int& size) const; TPrinter_setup_mask(); virtual ~TPrinter_setup_mask(); }; void TPrinter_setup_mask::set_print_rcd(PRINT_RCD* pcd, int size) { _pcd = pcd; _pcd_size = size; xvt_print_get_name(pcd, _pdev.get_buffer(), _pdev.size()); } PRINT_RCD* TPrinter_setup_mask::get_print_rcd(int& size) const { size = _pcd_size; return _pcd; } void TPrinter_setup_mask::fill_font_list() { const int MAX_FAMILIES = 256; char* family[MAX_FAMILIES]; const int num_families = (int)xvt_fmap_get_families(_pcd, family, MAX_FAMILIES); TToken_string fn(256); for (int i = 0; i < num_families; i++) { fn.add(family[i]); xvt_mem_free(family[i]); } TList_field& lst = (TList_field&)field(MSK_FONT); lst.replace_items(fn, fn); // Controlla se il font c'e' ancora if (fn.get_pos(_font) < 0) _font = fn.get(0); set(MSK_FONT, _font, 0x1); } void TPrinter_setup_mask::fill_size_list() { const int MAXSIZES = 128; long sizes[MAXSIZES]; BOOLEAN scalable; const int num_sizes = (int)xvt_fmap_get_family_sizes(_pcd, _font.get_buffer(), sizes, &scalable, MAXSIZES); TToken_string pn1; if (scalable) { for (int i = 4; i <= 32; i++) pn1.add(i); } else { if (num_sizes > 0) { for (int i = 0; i < num_sizes; i++) pn1.add(sizes[i]); } else pn1.add(printer().get_char_size()); // semper better than nothing } TList_field& lst = (TList_field&)field(MSK_SIZE); const TString8 old_size = lst.get(); lst.replace_items(pn1, pn1); lst.set(old_size); lst.enable(pn1.items() > 1); } bool TPrinter_setup_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { if (_skip_events) return TRUE; switch (o.dlg()) { case MSK_PRINTERS: if (fe_modify) { const TString& pdev = o.get(); // Nome stampante corrente if (pdev != _pdev) { TWait_cursor hourglass; if (_pcd != NULL) xvt_print_destroy(_pcd); _pcd = xvt_print_create_by_name(&_pcd_size, pdev); _pdev = pdev; fill_font_list(); } } break; case MSK_FONT: if (e == fe_modify) { TWait_cursor hourglass; const TString& family = o.get(); if (_font != family) { _font = family; fill_size_list(); } } break; case DLG_SETPRINT: if (e == fe_button) { if (xvt_dm_post_page_setup(_pcd)) { // see if user has changed printer // determine name of currently selected printer TString name; xvt_print_get_name(_pcd, name.get_buffer(), name.size()); set(MSK_PRINTERS, name, 0x1); } } break; default: break; } return TRUE; } TPrinter_setup_mask::TPrinter_setup_mask() : TAutomask("bagn001a") { TPrinter& pr = printer(); set(MSK_FILENAME, pr.get_printerfile()); const bool can_save = pr._config == "Printer"; enable(DLG_OK, can_save); set_print_rcd(pr._print_rcd, pr._print_rcd_size); // Crea la lista delle stampanti TToken_string pn2; SLIST plist = xvt_print_list_devices(); for (SLIST_ELT pitem = xvt_slist_get_first(plist); pitem != NULL; pitem = xvt_slist_get_next(plist, pitem)) { const char* pname = xvt_slist_get(plist, pitem, NULL); pn2.add(pname); } xvt_slist_destroy(plist); _skip_events = TRUE; if (pr._printertype == fileprinter) set (MSK_TYPE, "1"); else if (pr._printertype == screenvis) set(MSK_TYPE, "2"); else set(MSK_TYPE, "0"); TList_field& plst = (TList_field&)field (MSK_PRINTERS); plst.replace_items(pn2, pn2); // Genera printer list set(MSK_PRINTERS, pr._prname); _font = pr._fontname; fill_font_list(); fill_size_list(); set(MSK_FONT, _font); // Fare solo quando la lista e' piena set(MSK_SIZE, pr._ch_size); // Fare solo quando la lista e' piena set(MSK_LINES, pr._lines_per_inch); set(MSK_ISGRAPHICS, pr.isgraphics() ? "X" : ""); _skip_events = FALSE; } TPrinter_setup_mask::~TPrinter_setup_mask() { } /////////////////////////////////////////////////////////// // TPrinter /////////////////////////////////////////////////////////// TPrinter& printer() { if (_printer == NULL) _printer = new TPrinter; return *_printer; } void printer_destroy() { if (_printer != NULL) { delete _printer; _printer = NULL; } } // ---------------------------------------------------------------------- // TPrint_intersector // ---------------------------------------------------------------------- // TPrint_intersector: calcola intersezioni tra elementi grafici e // restituisce, riga per riga, i necessari caratteri di fincatura per // finculare in modo carattere // usata da viswin e printwin class TPrint_intersector : public TString_array { const char* _fink; char check_intersection(int x, int y, char ch); void h_line(int x1, int y1, int len); void v_line(int x1, int y1, int len); // caratteri fincazione: l'ho fatto perche' e' inline char f_topleft() const { return _fink[0]; } char f_topmiddle() const { return _fink[1]; } char f_topright() const { return _fink[2]; } char f_botleft() const { return _fink[3]; } char f_botmiddle() const { return _fink[4]; } char f_botright() const { return _fink[5]; } char f_centerleft() const { return _fink[6]; } char f_centermiddle() const { return _fink[7]; } char f_centerright() const { return _fink[8]; } char f_horizontal() const { return _fink[9]; } char f_vertical() const { return _fink[10]; } public: // aggiunge un elemento grafico void add(TGraphic_shape s, int x1, int y1, int x2, int y2); // aggiunge alla stringa passata i necessari caratteri, leggendo // dalla pagina interna const char* get_chars(int line) const; // sbianca tutto void clear(); TPrint_intersector(const char* fink, int pagesize) : TString_array(pagesize) , _fink(fink) {} virtual ~TPrint_intersector() {} }; char TPrint_intersector::check_intersection(int x, int y, char ch) { char a = ' ', b = ' ', c = ' ', d = ' '; if (y > 0 && objptr(y-1) != NULL) b = row(y-1)[x]; if (objptr(y+1) != NULL) d = row(y+1)[x]; if (x > 0) a = row(y)[x-1]; if (x < row(y).len()-1) c = row(y)[x+1]; if (a == ' ' && b == ' ' && c != ' ' && d != ' ') ch = f_topleft(); else if (a == ' ' && b != ' ' && c != ' ' && d == ' ') ch = f_botleft(); else if (a != ' ' && b != ' ' && c == ' ' && d == ' ') ch = f_botright(); else if (a != ' ' && b == ' ' && c == ' ' && d != ' ') ch = f_topright(); else if (a != ' ' && b != ' ' && c == ' ' && d != ' ') ch = f_centerright(); else if (a == ' ' && b != ' ' && c != ' ' && d != ' ') ch = f_centerleft(); else if (a != ' ' && b != ' ' && c != ' ' && d == ' ') ch = f_botmiddle(); else if (a != ' ' && b == ' ' && c != ' ' && d != ' ') ch = f_topmiddle(); else if ((a != ' ' && b != ' ' && c != ' ' && d != ' ') || ((a != ' ' && b == ' ' && c != ' ' && d == ' ') && ch == f_vertical()) || ((a == ' ' && b != ' ' && c == ' ' && d != ' ') && ch == f_horizontal())) ch = f_centermiddle(); return ch; } void TPrint_intersector::h_line(int x1, int y1, int len) { if (objptr(y1) == NULL) { TString* ss = new TString(256); ss->spaces(); TArray::add(ss, y1); } TString& s = row(y1); int i; for (i = x1; i < x1+len; i++) s[i] = f_horizontal(); for (i = x1; i < x1+len; i++) s[i] = check_intersection(i, y1, f_horizontal()); } void TPrint_intersector::v_line(int x1, int y1, int len) { int i; for (i = y1; i < y1+len; i++) { if (objptr(i) == NULL) { TString* ss = new TString(256); ss->spaces(); TArray::add(ss, i); } row(i)[x1] = f_vertical(); } for (i = y1; i < y1+len; i++) row(i)[x1] = check_intersection(x1, i, f_vertical()); } void TPrint_intersector::add(TGraphic_shape s, int x1, int y1, int x2, int y2) { // rows start at 0 y1 --; y2 --; // columns pure, ma e' possibile che siano gia' 0 se la generazione // e' stata automatica (colonna 1. campo - 1) if (x1 > 0) x1 --; if (x2 > 0) x2 --; switch (s) { case line: if (x1 == x2) // vertical v_line(x1, y1, y2-y1+1); else if (y1 == y2) // horizontal h_line(x1,y1, x2-x1+1); else error_box("Linee oblique non supportate in modalita' testo"); break; case box: h_line(x1, y1, x2-x1+1); h_line(x1, y2, x2-x1+1); v_line(x1, y1, y2-y1+1); v_line(x2, y1, y2-y1+1); break; default: break; } } const char* TPrint_intersector::get_chars(int line) const { if (objptr(line) == NULL) return ""; else return row(line); } void TPrint_intersector::clear() { for (int i = 0; i < items(); i++) { TString* s = (TString*)objptr(i); if (s != NULL) s->spaces(); } } /////////////////////////////////////////////////////////// // TPrint_txt_info /////////////////////////////////////////////////////////// struct TPrint_txt_info { TTextfile* _txt; word _copies; word _pagefrom; word _pageto; word _lastpage; bool edit(); TPrint_txt_info(TTextfile& txt); }; bool TPrint_txt_info::edit() { TPrinter& p = printer(); TMask msk("bagn003"); msk.set(F_PRINTER, p.printername()); msk.set(F_FORM, p.get_form_name()); msk.set(F_FONT, p.fontname()); msk.set(F_SIZE, p.get_char_size()); msk.set(F_ISGRAPHICS, p.isgraphics() ? "X" : ""); msk.set(F_FROMPAGE, _pagefrom); msk.set(F_TOPAGE, _lastpage); msk.set(F_COPIES, _copies); const bool ok = msk.run() == K_ENTER; if (ok) { _copies = msk.get_int(F_COPIES); _pagefrom = msk.get_int(F_FROMPAGE); _pageto = msk.get_int(F_TOPAGE); if (_pageto < _pagefrom || _pageto >= _lastpage) _pageto = 0; } return ok; } TPrint_txt_info::TPrint_txt_info(TTextfile& txt) : _txt(&txt), _copies(1), _pagefrom(1), _pageto(0) { const word ps = printer().formlen(); const long li = txt.lines(); _lastpage = (li+ps-1) / ps; } // @cmember Ritorna vero se la stampante e' generica/solo testo bool TPrinter::is_generic() const { bool yes = _dots_per_line == 1; if (!yes) yes = _prname.find("Generic") >= 0; return yes; } // @cmember Ritorna vero se sono attivati gli elementi grafici bool TPrinter::isgraphics() const { return _isgraphics; } // @cmember Attivati gli elementi grafici se possibile bool TPrinter::set_graphics(bool g) { _isgraphics = g && !is_generic(); return _isgraphics; } BOOLEAN TPrinter::start_print(long data) { const TPrint_txt_info *pd = (TPrint_txt_info *) data; TTextfile& txt = *(pd->_txt); TPrinter& stampante = printer(); const int vofs = stampante.get_line_offset(); const int hofs = stampante.get_column_offset(); if (stampante.is_generic() && (vofs != 0 || hofs != 0)) { TTextfile new_txt; TString s(256); const long last_row = txt.lines(); long out_row = 0; for (long row = (vofs < 0 ? -vofs : 0); row < last_row; row++) { const int pagelen = stampante.formlen(); const int page_row = (int) (out_row % pagelen); if (vofs > 0 && page_row == 0) { const int page = (int) (out_row / pagelen); for (int i = vofs; i > 0; i--) { out_row++; if (page > 0) row++; new_txt.append(""); } } if (vofs < 0 && page_row == pagelen + vofs) { for (int i = -vofs; i > 0; i--) { out_row++; row++; new_txt.append(""); } } s = txt.line(row); if (hofs < 0) s.ltrim(-hofs); else if(hofs > 0) s.lpad(s.len() + hofs); new_txt.append(s); out_row++; } TPrintwin pw(new_txt); pw.do_print(pd->_pagefrom, pd->_pageto, pd->_copies); return pw.aborted(); } else { TPrintwin pw(txt); if (pw.win() != NULL_WIN) pw.do_print(pd->_pagefrom, pd->_pageto, pd->_copies); return pw.aborted(); } } // utils del caz HIDDEN int read_int (const char *s, int &n, int &cnt) { char nbuf[16]; while (!isdigit (s[cnt])) cnt++; int j; for (j = 0; isdigit (s[cnt]); j++) nbuf[j] = s[cnt++]; nbuf[j] = '\0'; return n = atoi (nbuf); } void TPrinter::parse_background(const char* bg_desc, TString_array& background) { TString_array pix; char op, ch; int x1, x2, y1, y2; int id, cnt = 0; TToken_string tt; TFilename bmp; if (!_fink_mode && _finker == NULL) _finker = new TPrint_intersector(_fink, _formlen); else if (_finker) _finker->clear(); while ((ch = bg_desc[cnt++]) != '\0') { op = ch; tt = ""; char bf[2]; bf[1] = '\0'; switch (op) { case ' ': case '\t': case '\n': continue; // ignore whitespace break; case 'i': cnt++; for (x1 = 0; bg_desc[cnt] != ','; x1++) bmp[x1] = bg_desc[cnt++]; bmp[x1] = '\0'; id = _image_names.find(bmp); if (id < 0) id = _image_names.add(bmp); read_int(bg_desc, x1, cnt); if (x1 <= 0) x1 = 1; read_int(bg_desc, y1, cnt); if (y1 <= 0) y1 = 1; read_int(bg_desc, x2, cnt); if (x2 <= 0) x2 = formwidth(); read_int(bg_desc, y2, cnt); if (y2 <= 0) y2 = formlen(); cnt++; if (_isgraphics) { tt << op; tt.add(id); tt.add(x1); tt.add(y1); tt.add(x2); tt.add(y2); } break; case 'l': // line case 'b': // box case 'r': // round box cnt++; read_int (bg_desc, x1, cnt); read_int (bg_desc, y1, cnt); read_int (bg_desc, x2, cnt); read_int (bg_desc, y2, cnt); cnt++; // skip separator if (_isgraphics && _fink_mode) { tt << op; tt.add (x1 - 1); tt.add (y1 - 1); tt.add (x2 - 1); tt.add (y2 - 1); } else { TGraphic_shape s = op == 'b' ? box : line; _finker->add(s, x1, y1, x2, y2); } break; case 't': // text cnt++; read_int (bg_desc, x1, cnt); read_int (bg_desc, y1, cnt); cnt++; tt << op; tt.add (x1-1); tt.add (y1-1); tt << '|'; while ((ch = bg_desc[cnt++]) != '}') tt << ch; break; case 'P': // set pen style case 'B': // set brush case 'W': // set line width case 'C': // set pen color tt << op; bf[0] = bg_desc[cnt++]; tt.add (bf); break; default: yesnofatal_box ("Unknown background opcode: %c", op); break; } pix.add (tt); } // now build row descriptions // colors are listed in printapp: char curcol = 'n'; char curpen = 'n'; char curpat = 'n'; char curwid = '1'; for (int l = 0; l < _formlen; l++) { if (background.objptr(l) == NULL) // Se la riga non esiste creala { TToken_string* r = new TToken_string(15); if (curcol != 'n') *r << 'C' << curcol; // Setta valori se diversi da default if (curpat != 'n') *r << 'B' << curpat; if (curwid != '1') *r << 'W' << curwid; if (curpen != 'n') *r << 'P' << curcol; background.add(r, l); } TString& rwd = background.row(l); for (int j = 0; j < pix.items(); j++) { TToken_string& tt = pix.row(j); // la stringa contiene l'opcode piu' i parametri in binario, // incrementati di 1 per evitare lo 0 switch (tt.get_char(0)) { case 'b': x1 = tt.get_int (1) + 1; y1 = tt.get_int (2) + 1; x2 = tt.get_int (3) + 1; y2 = tt.get_int (4) + 1; if (y1 == l + 1) // at ze biginnin { rwd << 'u' << char (x1); rwd << 'r' << char (x1) << char (x2); rwd << 'u' << char (x2); } else if (y2 == l + 1) // at ze end { rwd << 'o' << char (x1); rwd << 'r' << char (x1) << char (x2); rwd << 'o' << char (x2); } else if (y1 < l + 1 && y2 > l + 1) // in ze middol { rwd << 'v' << char (x1); rwd << 'v' << char (x2); } break; case 'l': x1 = tt.get_int (1) + 1; y1 = tt.get_int (2) + 1; x2 = tt.get_int (3) + 1; y2 = tt.get_int (4) + 1; if (y1 == y2 && y1 == l + 1) // orizzontale { rwd << 'h' << char (x1) << char (x2); } else if (y1 <= l + 1 && y2 >= l + 1) // verticale { rwd << 'v' << char (x1); } break; case 'r': x1 = tt.get_int (1) + 1; y1 = tt.get_int (2) + 1; x2 = tt.get_int (3) + 1; y2 = tt.get_int (4) + 1; if (y1 == y2) // orizzontale { if (y1 == l+1) rwd << 'r' << char (x1) << char (x2); } else { const int l1 = l+1; if (l1 >= y1 && l1 <= y2) // verticale { char code = 'v'; if (y1 == l1) code = 'u'; else if (y2 == l1) code = 'o'; rwd << code << char(x1); } } break; case 't': x1 = tt.get_int (1) + 1; y1 = tt.get_int (2) + 1; // al gh'e' if (y1 == l + 1) {} break; case 'i': id = tt.get_int(); x1 = tt.get_int(); y1 = tt.get_int(); x2 = tt.get_int(); y2 = tt.get_int(); if (l+1 >= y1 && l+1 <= y2) rwd << 'i' << char(id+1) << char(l-y1+2) << char(x1) << char(x2-x1+1) << char(y2-y1+1); break; case 'W': curwid = *(tt.get (1)); rwd << 'W' << curwid; break; case 'P': curpen = *(tt.get (1)); rwd << 'P' << curpen; break; case 'B': curpat = *(tt.get (1)); rwd << 'B' << curpat; break; case 'C': curcol = *(tt.get (1)); rwd << 'C' << curcol; break; default: break; } } } } void TPrinter::setbackground(const char* b, int index) { CHECK(index >= 0 && index <= 3, "Bad background index"); _backgrounds.destroy(index); if (b && *b) { TString_array* bg = new TString_array(formlen()); _backgrounds.add(bg, index); parse_background(b, *bg); } } TString_array& TPrinter::getbgdesc(word page) const { int index = 0; if (page == 0 && _backgrounds.objptr(3)) index = 3; if (page == 1 && _backgrounds.objptr(2)) index = 2; if (index == 0 && (page & 0x1) == 0 && _backgrounds.objptr(1)) index = 1; TString_array* bg = (TString_array*)_backgrounds.objptr(index); if (bg == NULL) { bg = new TString_array(formlen()); ((TPrinter*)this)->_backgrounds.add(bg, index); // keep const } return *bg; } //bool printers_on_key(TMask_field & f, KEY key); ////////// TPRINTROW ////////// TPrintrow::TPrintrow() { reset(); } TPrintrow::TPrintrow(const TPrintrow& pr) { reset(); _row = pr.row (); memcpy (_attr, pr._attr, MAX_PR_WIDTH); memcpy (_cols, pr._cols, MAX_PR_WIDTH); _tab = pr._tab; if (pr._images) _images = new TToken_string(*pr._images); _currentstyle = pr._currentstyle; _currentcolor = pr._currentcolor; _lastpos = pr._lastpos; } TPrintrow::~TPrintrow() { if (_images) delete _images; } TObject *TPrintrow::dup () const { return new TPrintrow (*this); } const char *TPrintrow::class_name () const { return "Printrow"; } word TPrintrow::class_id() const { return CLASS_PRINTROW; } TPrintrow& TPrintrow::reset() { _row.spaces (sizeof(_attr)); // Azzera testo memset(_attr, normalstyle, sizeof (_attr)); // Azzera stile _tab.reset(); // Azzera tabulazioni _images = NULL; _currentcolor = 'w'; _currentcolor <<= 8; _currentcolor += 'n'; for (int i = 0; i < MAX_PR_WIDTH; i++) _cols[i] = _currentcolor; // Azzera colori _lastpos = 0; _currentstyle = normalstyle; return *this; } const char* TPrintrow::row_codified() const { char last_attr = -1; int last_color = -1; int k = 0, i = 0, len = 0; char* tmp = get_tmp_string(256).get_buffer(); // Calcolo lunghezza stringa for (i = _row.size()-1; i >= 0; i--) { if (_row[i] != ' ') { len = i+1; break; } } for (i = 0; i < len; i++) { if (_tab[i]) { tmp[k++] = '@'; tmp[k++] = 't'; } if (_attr[i] != last_attr) { tmp[k++] = '@'; switch (_attr[i]) { case normalstyle: tmp[k++] = 'r'; break; case boldstyle: tmp[k++] = 'b'; break; case italicstyle: tmp[k++] = 'i'; break; case underlinedstyle: tmp[k++] = 'u'; break; } last_attr = _attr[i]; } if (_cols[i] != last_color) { tmp[k++] = '$'; tmp[k++] = '['; tmp[k++] = (char) (_cols[i] & 0x00ff); tmp[k++] = ','; tmp[k++] = (char) (_cols[i] >> 8); tmp[k++] = ']'; last_color = _cols[i]; } if (_row[i] == '@' && strchr("<#>", _row[i+1]) == NULL) tmp[k++] = '@'; // Escape for @ tmp[k++] = _row[i]; } tmp[k] = '\0'; if (_images) { strcat(tmp, "$[w,w]"); // Bianco su bianco! FOR_EACH_TOKEN((*_images), tok) strcat(tmp, tok); } return tmp; } TPrintrow& TPrintrow::put(const char *str, int position, int len) { if (len <= 0) len = strlen (str); if (position < 0) position = _lastpos; else _tab.set(position); char bg = 'w', fg = 'n'; for (int i = 0; i < len; i++) { char c = str[i]; if (c == '$' && str[i + 1] == '[') { ++i; fg = str[++i]; c = str[++i]; if (c == ']') bg = _currentcolor >> 8; else if (c == ',') { bg = str[++i]; i++; } else { CHECK (0, "Error in color specification"); } _currentcolor = (bg << 8) + fg; } else if (c == '@') { c = str[++i]; switch (toupper (c)) { case '@': // Escape for @ _row[position] = '@'; _attr[position] = _currentstyle; _cols[position++] = _currentcolor; break; case '#': case '<': case '>': // printer MUST handle them { const int n = (c == '#') ? 5 : ((c == '>') ? 10 : 8); _row[position] = '@'; _attr[position] = _currentstyle; _cols[position++] = _currentcolor; for (int j = 1; j < n; j++) { _row[position] = c; _attr[position] = _currentstyle; _cols[position++] = _currentcolor; } } break; case 'T': _tab.set(position); break; case 'B': _currentstyle = boldstyle; break; case 'I': _currentstyle = italicstyle; break; case 'U': _currentstyle = underlinedstyle; break; case 'R': _currentstyle = normalstyle; break; case 'F': { const int f = i; for ( ; str[i] && str[i] != ']'; i++); TString name = &str[f+2]; name.cut(i-f-2); name.insert("i{"); name << '}'; if (_images == NULL) _images = new TToken_string; _images->add(name); } break; default: // should be number followed by skip or jump if (isdigit (c)) { // read number char digbuf[8]; int cnt = 0; digbuf[cnt++] = c; while (isdigit (c = str[++i])) digbuf[cnt++] = c; digbuf[cnt] = '\0'; int pp = atoi (digbuf); if (toupper (c) == 'G') { if (pp >= MAX_PR_WIDTH) fatal_box ("printrow reaches position %d", pp); if (pp > position) for (int k = position; k < pp; k++) { _attr[k] = _currentstyle; _cols[k] = _currentcolor; } position = pp; _tab.set(position); } else if (toupper (c) == 'J') { if (pp + position >= MAX_PR_WIDTH) fatal_box ("printrow reaches position %d", pp + position); for (int k = 0; k < pp; k++) { _attr[k + position] = _currentstyle; _cols[k + position] = _currentcolor; } position += pp; _tab.set(position); } } else { _row[position] = c; _attr[position] = _currentstyle; _cols[position++] = _currentcolor; } } // switch } else { _row[position] = c; _attr[position] = _currentstyle; _cols[position++] = _currentcolor; } } // for _lastpos = position; return *this; } ////////// TPRINTER ////////// void TPrinter::set_printrcd() { if (_print_rcd != NULL) { xvt_print_destroy(_print_rcd); _print_rcd = NULL; _print_rcd_size = 0; } bool ok = false; if (_prname.not_empty()) { _print_rcd = xvt_print_create_by_name(&_print_rcd_size, _prname); ok = xvt_print_is_valid(_print_rcd) != 0; } if (!ok) { _print_rcd = xvt_print_create(&_print_rcd_size); xvt_print_get_name(_print_rcd, _prname.get_buffer(), _prname.size()); ok = xvt_print_is_valid(_print_rcd) != 0; } if (!ok) error_box(FR("Errore di inizializzazione della stampante %s"), (const char*)_prname); } PRINT_RCD* TPrinter::get_printrcd(int *size) { if (_print_rcd == NULL) set_printrcd(); if (size != NULL) *size = _print_rcd_size; return _print_rcd; } // @doc EXTERNAL // @mfunc Setta le caratteristiche della stampante leggendole da

void TPrinter::init_formlen( WINDOW prwin) // @parm Finestra effettiva di stampa (default NULL_WIN) // @comm Nel caso

sia NULL_WIN vengono solamente aggiornati i valori { long pw, ph, phr, pvr; // Printer width, height, horizontal and vertical resolution xvt_app_escape (XVT_ESC_GET_PRINTER_INFO, get_printrcd(), &ph, &pw, &pvr, &phr); if (pvr > 0) { _formlen = int(ph * _lines_per_inch / pvr); // Total number of lines per page _dots_per_line = int(pvr / _lines_per_inch); // Number of point per line _vert_offset = (int)(ph - ((long)_formlen * _dots_per_line)) >> 1; if (prwin != NULL_WIN) { // Compute maximum number of chars per line int mincol = 0,maxcol=MAX_PR_WIDTH; TString256 spc; spc.fill('m', maxcol); _formwidth = maxcol; int w = 0; while (mincol < maxcol ) { w = xvt_dwin_get_text_width(prwin, (char*)(const char*)spc, _formwidth); if (w < pw) mincol = _formwidth+1; else maxcol=_formwidth-1; _formwidth=(mincol+maxcol)/2; } _horz_offset = (_formwidth > 80) ? (int)(pw - w)/2 : 0; if (_horz_offset < 0) _horz_offset = 0; } else { _formwidth = int (pw * (_ch_size * 10 / 12) / phr); _horz_offset = 0; } } } TPrinter::TPrinter() : _vf(NULL), _ch_size (12), _date (TODAY), _multiple_link (FALSE), _isgraphics (TRUE), _frozen (FALSE), _print_rcd(NULL), _lines_per_inch (6), _l_offset(0), _c_offset(0), _export_header(FALSE), _export_header_len(0), _appendfile(FALSE) { _footerhandler = _headerhandler = NULL; _linkhandler = NULL; _formlen = 66; _formwidth = 0; _frompage = 0; _topage = 0xffff; _hwformfeed = FALSE; _currentpage = 1; _currentrow = 1; _fp = NULL; _headersize = 0; _footersize = 0; _isopen = FALSE; // xvt_print_get_default_device(_defPrinter.get_buffer(), _defPrinter.size()); // read configuration file read_configuration (); init_formlen (); set_fincatura("+++++++++-|"); set_fink_mode(TRUE); _finker = _isgraphics && _fink_mode ? NULL : new TPrint_intersector(_fink, _formlen); } // @doc EXTERNAL // @mfunc Legge la configurazione della stampante void TPrinter::read_configuration( const char* parag) // parm Nome del file di configurazione della stampante (default NULL) // @comm Se

e' NULL viene letta la configurazione della stamapnte di default. { TWait_cursor hourglass; _config = parag; // Inizializza nome configurazione if (_config.empty()) // Se non specificata ... _config = "Printer"; // ... usa configurazione standard TConfig* iniptr = NULL; if (_config != "Printer") // Cerca configurazione speciale { iniptr = new TConfig(CONFIG_STAMPE, _config); const int what = iniptr->get_int("Type", NULL, -1, -1); if (what < 0) // Se configurazione annullata ... { delete iniptr; iniptr = NULL; } } if (iniptr == NULL) iniptr = new TConfig(CONFIG_GUI, "Printer"); const int what = iniptr->get_int("Type", NULL, -1, 4); // Tipo stampante _prname = iniptr->get("Name", NULL, -1, _defPrinter); // Nome stampante corrente _printerfile = iniptr->get("File", NULL, -1, ""); // File di stampa set_fontname(iniptr->get("Font", NULL, -1, XVT_FFN_FIXED)); // Nome del font _ch_size = iniptr->get_int("Size", NULL, -1, 10); // Dimensione del font _lines_per_inch = iniptr->get_int("Lines", NULL, -1, 6); // Linee per pollice set_graphics(iniptr->get_bool("Graphic", NULL, -1, TRUE)); // Grafica attiva bool read_rcd = FALSE; const TString& host = iniptr->get("Host"); if (host.not_empty()) { char hostname[32]; xvt_sys_get_host_name(hostname, sizeof(hostname)); read_rcd = (host == hostname); // Safe to read if (!read_rcd) { read_rcd = yesno_box(FR("Attenzione: le impostazioni della stampante sono relative alla stazione di lavoro %s.\n" "Si desidera utilizzarle ugualmente sulla stazione %s?"), (const char*)host, hostname); if (!read_rcd) { // Forza la lettura parametri della stampante di default _prname.cut(0); set_printrcd(); } } } if (read_rcd) { if (_print_rcd != NULL) xvt_print_destroy(_print_rcd); _print_rcd = xvt_print_create_by_name(&_print_rcd_size, _prname); if (xvt_print_is_valid(_print_rcd) && iniptr->exist("rcd", 0)) { TToken_string s(256); int i = 0; for (int index = 0; ; index++) { s = iniptr->get("rcd", NULL, index); if (s.not_empty()) { byte* rcd = (byte*)_print_rcd; for (const char* n = s.get(0); n != NULL && i < _print_rcd_size; n = s.get()) rcd[i++] = (byte)atoi(n); } else break; } } if (xvt_print_is_valid(_print_rcd)) { init_formlen(); xvt_print_get_name(_print_rcd, _prname.get_buffer(), _prname.size()); } else { error_box("Attenzione: la stampante corrente non e' valida.\n" "Si prega di selezionare e registrare una nuova stampante."); set_printrcd(); } } delete iniptr; iniptr = NULL; if (_printerfile.empty()) { _printerfile.tempdir(); _printerfile << SLASH; } if (_config == "Printer" || _printertype == winprinter) { switch (what) { case 1: _printertype = fileprinter; break; case 2: _printertype = screenvis; break; case 3: _printertype = exportprinter; break; default: _printertype = winprinter; break; } } } void TPrinter::save_configuration() { TWait_cursor hourglass; CHECK(_config.not_empty(), "Invalid printer config"); TConfig prini(_config == "Printer" ? CONFIG_GUI : CONFIG_STAMPE, _config); prini.set("Type", _printertype); // Tipo stampante prini.set("Name", _prname); // Nome stampante corrente prini.set("File", _printerfile); // File di stampa prini.set("Font", _fontname); // Nome del font prini.set("Size", _ch_size); // Dimensione del font prini.set("Lines", _lines_per_inch); // Linee per pollice prini.set("Graphic", _isgraphics ? "X" : ""); // Grafica attiva char hostname[80]; xvt_sys_get_host_name(hostname, sizeof(hostname)); prini.set("Host", hostname); prini.set("User", user()); int n = 0, index = 0; TToken_string val(256); int rcdsize; byte* rcd = (byte*)get_printrcd(&rcdsize); for (int i = 0; i < rcdsize; i++) { val.add((int)rcd[i]); n++; if (n == 24) { prini.set("rcd", val, NULL, TRUE, index++); val.cut(n = 0); } } if (n > 0) prini.set("rcd", val, NULL, TRUE, index); for (index++; prini.remove("rcd", index); index++); } TPrinter::~TPrinter () { if (_print_rcd != NULL) { xvt_print_destroy(_print_rcd); _print_rcd = NULL; } // xvt_print_set_default_device(_defPrinter); } const char* TPrinter::class_name() const { return "Printer"; } word TPrinter::class_id() const { return CLASS_PRINTER; } TPrintrow *TPrinter::getheaderline(int linetoget) { return ((TPrintrow *)_header.objptr (linetoget)); } TPrintrow *TPrinter::getfooterline(int linetoget) { return ((TPrintrow *)_footer.objptr(linetoget)); } // @doc EXTERNAL // @mfunc Setta il contenuto di una line dell'header void TPrinter::setheaderline ( int linetoset, // @parm Numero della linea da settare TPrintrow * line) // @parm Contenuto della linea dell'header // @parm const TPrintrow& | line | Indirizzo con il contenuto della // linea dell'header // @syntax void setheaderline (int linetoset, TPrintrow* line); // @syntax void setheaderline (int linetoset, const TPrintrow& line); { _header.add (line, linetoset); if (linetoset >= _headersize) _headersize = linetoset + 1; } void TPrinter::setheaderline (int linetoset, const TPrintrow & line) { TPrintrow *p = new TPrintrow (line); setheaderline (linetoset, p); } // @doc EXTERNAL // @mfunc Setta il contenuto di una line dell'header void TPrinter::setfooterline ( int linetoset, // @parm Numero della linea da settare TPrintrow * line) // @parm Contenuto della linea del footer // @parm const TPrintrow& | line | Indirizzo con il contenuto della // linea del footer // @syntax void setfooterline (int linetoset, TPrintrow* line); // @syntax void setfooterline (int linetoset, const TPrintrow& line); { _footer.add (line, linetoset); } void TPrinter::setfooterline (int linetoset, const TPrintrow& line) { TPrintrow *p = new TPrintrow (line); setfooterline (linetoset, p); } void TPrinter::resetheader () { _header.destroy (); _headersize = 0; } void TPrinter::resetfooter () { _footer.destroy (); // _footersize = 0; } // @doc EXTERNAL // @mfunc Metodo base per la stampa // // @rdesc Ritorna il risulato della stampa: // // @flag TRUE | Se la stampa ha avuto successo // @flag FALSE | Se la stampante non e' attiva bool TPrinter::printrow( TPrintrow* rowtoprint) // @parm Riga da stampare // @comm Se la pagina logica corrente e' precedente alla prima pagina logica o successiva // all'ultima pagina logica viene ritornato TRUE. { if (!isopen ()) return FALSE; if (_currentpage < _frompage || _currentpage > _topage) return TRUE; TString rw (rowtoprint == NULL ? "" : ((_printertype == screenvis || _printertype == winprinter || _printertype == exportprinter) ? rowtoprint->row_codified () : rowtoprint->row ())); rw.rtrim (); int lun = rw.len (); int idx; if (_printertype != exportprinter) { for (idx = 0; idx < lun; idx++) { if (rw[idx] == '@') // gestione data e n. di pagina { switch (rw[idx + 1]) { case '#': rw.overwrite (format("%-5u", _currentpage), idx++); break; case '>': rw.overwrite (_date.string(full), idx++); break; case '<': rw.overwrite (_date.string(brief), idx++); break; default: break; } } } } if (_printertype == screenvis) { if (!_vf->frozen ()) _vf->add_line(rw); else _frozen = TRUE; return TRUE; } if (_printertype == winprinter || _printertype == exportprinter) { // add line to txt if (!_frozen) _txt.append(rw); return TRUE; } if (_printertype == fileprinter) { // add line to txt if (!_frozen) _txt.append (rw); return TRUE; } return TRUE; } word TPrinter::rows_left() const { word left = _formlen - _currentrow - _footersize + 1; if (_currentrow < 2) left -= _headersize; return left; } // @doc EXTERNAL // @mfunc Permette di stampare una riga // // @rdesc Ritorna il risultato della stampa: // // @flag TRUE | Se la stampa ha avuto successo // @flag FALSE | Se non e' riuscito ad effettuare la stampa bool TPrinter::print( TPrintrow& rowtoprint) // @parm Riga da stampare // @comm Nel caso la riga non ci stia nella pagina logica corrente vengono stampanti il footer // della pagina corrente e l'header della successiva prima prima della stampa della riga // vera e propria. { bool ok = TRUE; if (!(_printertype == exportprinter && !_export_header)) { if (_currentrow > _formlen - _footersize) ok = printfooter (); if (ok && _currentrow == 1) ok = printheader(); } if (ok) { ok = printrow(&rowtoprint); _currentrow++; } return ok; } bool TPrinter::printheader() { if (_headerhandler) _headerhandler(*this); bool ok = TRUE; int i; for (i = 0; i < _headersize && ok; i++) ok = printrow(getheaderline(i)); // _currentrow = _headersize + 1; _currentrow = i+1; return ok; } bool TPrinter::printfooter() { if (_footerhandler) _footerhandler (*this); bool ok = TRUE; for (int i = 0; i < _footersize && ok; i++) ok = printrow(getfooterline(i)); _currentrow = 1; _currentpage++; return ok; } // @doc EXTERNAL // @mfunc Permette di settare il tipo di fincatura void TPrinter::set_fink_mode( bool f) // @parm Indica il tipo di fincatura: // // @flag TRUE | Fincatura di tipo grafico // @flag FALSE | Fincatura di tipo testo // @comm Viene prima controllato che la stampante supporti la modalita' grafica, // in tal caso, se viene impostato il flag a TRUE e la stampante e' generica // oppure non ha il flag di stampa elementi grafici attivato, la fincatura sara' // in modo testo. { _fink_mode = f && isgraphics(); } // @doc EXTERNAL // @mfunc Permette di saltare alcune righe dalla posizione corrente // // @rdesc Ritorna il risulato dell'operazione: // // @flag TRUE | Se e' riuscito a saltare le righe // @flag FALSE | Se non e' riuscito a saltare le righe bool TPrinter::skip( int linestoskip) // @parm Vengono accettati solo valori positivi // @xref { CHECK (linestoskip >= 0, "Linestoskip can't be negative"); int jumpline = _currentrow + linestoskip; return jump(jumpline); } // @doc EXTERNAL // @mfunc Permette di saltare alla riga indicata // // @rdesc Ritorna il risultato dell'operazione // // @flag TRUE | Se e' riuscito a saltare alla riga // @flag FALSE | Se non e' riuscito a saltare alla riga o se viene inserito un formfeed bool TPrinter::jump( int jumpline) // @parm Numero della riga a cui saltare nella stampa. Vengono accettai // solo valori positivi // @comm Nel caso si cerchi di saltare ad una riga superiore alla lunghezza della pagina attiva // viene inserito un formfeed. // @xref { int i = 0; bool ok = TRUE; CHECK (jumpline >= 0, "Jumpline can't be negative"); if (jumpline > _formlen - _footersize) ok = formfeed(); else for (i = _currentrow; i < jumpline; i++) if (!printrow()) ok = FALSE; if (jumpline > _formlen - _footersize) ok = FALSE; return ok; } bool TPrinter::formfeed() { const int lastrow = _formlen - _footersize; for (; _currentrow + _export_header_len <= lastrow; _currentrow++) printrow(); return printfooter(); } void TPrinter::reset() { resetheader(); resetfooter(); _currentpage = 1; _currentrow = 1; } bool TPrinter::open() { // xvt_print_set_default_device(_prname); if (_printertype == screenvis) { CHECK(_vf == NULL, "Print preview already open"); _vf = new TViswin (NULL, "Anteprima di stampa", TRUE, TRUE, _linksdescr.items () > 0); _vf->open_modal (); } else { if (_printertype == winprinter || _printertype == exportprinter || _printertype == fileprinter) { // prepare text object for new text _txt.destroy(); _txt.interactive(FALSE); } } _currentrow = 1; _currentpage = 1; return _isopen = TRUE; } bool TPrinter::set() { main_app().disable_menu_item(M_FILE_PG_SETUP); const TString oldprn = _prname; int old_rcd_size; PRINT_RCD* rcd = get_printrcd(&old_rcd_size); TString oldrcd(old_rcd_size); memcpy(oldrcd.get_buffer(), rcd, old_rcd_size); TPrinter_setup_mask mask; const KEY k = mask.run(); _print_rcd = mask.get_print_rcd(_print_rcd_size); if (k == K_ESC) { xvt_print_destroy(_print_rcd); _print_rcd = xvt_print_create_by_name(&_print_rcd_size, oldprn); memcpy(_print_rcd, oldrcd, _print_rcd_size); } else { _prname = mask.get(MSK_PRINTERS); switch (atoi (mask.get (MSK_TYPE))) { case 1: // file _printertype = fileprinter; _printerfile = mask.get (MSK_FILENAME); break; case 2: // video _printertype = screenvis; break; default: // stampante _printertype = winprinter; break; } set_fontname(mask.get(MSK_FONT)); const int cs = mask.get_int(MSK_SIZE); if (cs > 4) _ch_size = cs; _lines_per_inch = mask.get_int (MSK_LINES); _isgraphics = mask.get_bool (MSK_ISGRAPHICS); init_formlen (); if (k == K_INS) save_configuration(); } main_app().enable_menu_item (M_FILE_PG_SETUP); return TRUE; } // @doc EXTERNAL // @mfunc Inserisce un file di export fatto da un'altra printer void TPrinter::merge_export_file( const char* file, bool header) // @parm Indica se gli header sono presenti nel file: // // @flag TRUE | Gli header sono nel file e quindi non vengono stampanti (default) // @flag FALSE | Gli header non sono nel file e quindi vengono stampanti // @comm Vengono inseriti nel file di export i formati e tutto il resto. Vengono ignorati gli // header supponendo che siano gia' presenti nel file { TTextfile txt(file); for (long i = 0; i < txt.lines(); i++) { TPrintrow* p = new TPrintrow(); p->put(txt.line_formatted(i)); if (header) printrow(p); else print(*p); } } // @doc EXTERNAL // @mfunc Crea un segnalibro // // @rdesc Ritorna l'identificatore del segnalibro creato int TPrinter::set_bookmark( const char* txt, // @parm Nome del segnalibro da creare int father) // @parm Identificatore del segnalibro padre a cui collegare quello // da creare { if (_printertype == screenvis) { BkDef* bkd = new BkDef; bkd->_row = (_currentrow + ((_currentpage - 1)*_formlen)) - 1; bkd->_father_id = father; bkd->_id = _bookmarks.items() + 1; bkd->_txt = txt; _bookmarks.add(bkd); return _bookmarks.items(); } return 0; } void TPrinter::print_txt(TTextfile& txt) { if (txt.lines() > 0) { TPrint_txt_info what(txt); if (what.edit()) { xvt_print_open(); xvt_print_start_thread(start_print, long(&what)); xvt_print_close(); } } } void TPrinter::close () { if (isopen() && // la stampante era aperta e _currentrow >1 && // .. ho stampato qualcosa ... _footersize>0 ) // ... c'è footer da stampare formfeed(); if (_fp) { fclose (_fp); _fp = NULL; } if (_printertype == screenvis) { _vf->close_print(); const KEY key = _vf->run (); if (_vf->is_open ()) _vf->close_modal (); _bookmarks.destroy(); if (key == K_CTRL+'S') { _isopen = FALSE; _currentrow = _currentpage = 1; print_txt(_vf->text()); } delete _vf; _vf = NULL; } else if (_printertype == exportprinter) { if (_exportfile.not_empty() && _txt.lines() > 0L) { ofstream txt(_exportfile); for (long i = 0; i < _txt.lines(); i++) txt << _txt.line_formatted(i) << '\n'; txt.close(); } } else if (_printertype == winprinter && _txt.lines() > 0L) { print_txt(_txt); // xvt_print_set_default_device(_defPrinter); } else if (_printertype == fileprinter) { FILE* fp = fopen(_printerfile, _appendfile ? "a" : "w"); if (fp == NULL) { error_box(FR("Impossibile aprire il file %s"), (const char*)_printerfile); return; } for (long i = 0; i < _txt.lines(); i++) fprintf(fp,"%s\n", _txt.line(i)); fclose(fp); message_box(FR("Stampa su file terminata. Nome archivio: %s"),(const char *)_printerfile); } if (_finker) { delete _finker; _finker = NULL; } // Dealloca sfondi ormai inutili _backgrounds.destroy(); freeze (FALSE); _isopen = FALSE; } // // TFile_printer // #include const long disk_sizes[] = { 360000L, 1200000L, 720000L, 1400000L, 2880000L }; TFile_printer::TFile_printer (const char *ffile, const char *label, int len_rec, int num_rec_inizio, int num_rec_fine, int tipo_disco) { set_printtype (fileprinter); _num_rec_testa_coda = num_rec_inizio + num_rec_fine; _file = ffile; _label = label; _len_rec = len_rec; _volume = 1; _size = disk_sizes[tipo_disco]; _num_rec_volume = int ((_size / len_rec) - _num_rec_testa_coda); _nome_file_fissato = TRUE; _label_fissata = TRUE; } void TFile_printer::open() { } void TFile_printer::close () { } bool TFile_printer::genera_dischetti () { int r; for (int i = 0; i < _tmp_files.items (); i++) { // Avvisa l'utente di inserire un dischetto r = yesno_box ("Inserire il dischetto n. %2d di %2d nel drive %2s", i + 1, _volume, _drive); if (!r) return error_box ("Procedura interrotta!"); // copia il file sul dischetto fcopy ((const char *) &_tmp_files[i], (const char *) _drive); } return TRUE; } TFile_printer::~TFile_printer () { } bool TFile_printer::set () { TMask m ("bagn004"); int f; // // // -------------------------------------------------------------------- // Qui bisogna inserire la lista dei drive disponibili nella maschera // Per ora tale lista e' fissa e contiene solo A: e B: // -------------------------------------------------------------------- // // m.set (F_FILE_DESTINAZIONE, _file); m.set (F_LABEL, _label); if (_nome_file_fissato) m.disable (F_FILE_DESTINAZIONE); if (_label_fissata) m.disable (F_LABEL); const bool ok = m.run () == K_ENTER; if (ok) { f = atoi(m.get(F_FORMATO_DISCO)); _drive = m.get(F_DRIVE); _file = m.get(F_FILE_DESTINAZIONE); _label = m.get(F_LABEL); _size = disk_sizes[f]; _num_rec_volume = int ((_size / _len_rec) - _num_rec_testa_coda); } return ok; } const char* TPrinter::background_chars(int l) const { return _finker == NULL ? "" : _finker->get_chars(l); } /////////////////////////////////////////////////////////// // Calcolo dimensione font /////////////////////////////////////////////////////////// struct font_data { TString _name; int _size; int _columns; }; HIDDEN BOOLEAN calc_font_callback(long data) { font_data& fd = *(font_data*)data; // Create print window WINDOW win = xvt_print_create_win(printer().get_printrcd(), "Calcolo font"); if (win != NULL_WIN) { long pw, ph, phr, pvr; // Printer width, height, horizontal and vertical resolution xvt_app_escape (XVT_ESC_GET_PRINTER_INFO, printer().get_printrcd(), &ph, &pw, &pvr, &phr); TString test(fd._columns); test.fill('M', fd._columns); int size; for (size = fd._size; size > 0; size--) { // Set print font xvt_set_font(win, fd._name, XVT_FS_NONE, size); const int w = xvt_dwin_get_text_width(win, (char*)(const char*)test, fd._columns); if (w <= pw) break; } if (size > 0) fd._size = size; xvt_vobj_destroy(win); } return win != NULL_WIN; } int TPrinter::calc_font_size(int columns) const { font_data fd; fd._name = fontname(); fd._size = get_char_size(); fd._columns = columns; xvt_print_open(); xvt_print_start_thread(calc_font_callback, (long)&fd); xvt_print_close(); return fd._size; } HIDDEN BOOLEAN calc_cols_callback(long data) { int &numcols=*(int *)data; // Create print window WINDOW win = xvt_print_create_win(printer().get_printrcd(), "Calcolo numero colonne"); if (win != NULL_WIN) { long pw, ph, phr, pvr; // Printer width, height, horizontal and vertical resolution xvt_app_escape (XVT_ESC_GET_PRINTER_INFO, printer().get_printrcd(), &ph, &pw, &pvr, &phr); xvt_set_font(win, printer().fontname(), XVT_FS_NONE, printer().get_char_size()); // Compute maximum number of chars per line int mincol = 0,maxcol=MAX_PR_WIDTH; TString spc(maxcol,'M' ); numcols = maxcol; int w; while (mincol < maxcol ) { w = xvt_dwin_get_text_width(win, (char*)(const char*)spc, numcols); if (w < pw) mincol = numcols+1; else maxcol=numcols-1; numcols=(mincol+maxcol)/2; } xvt_vobj_destroy(win); } return win != NULL_WIN; } // Funzione chiamata solo da sv1200, ma non si capisce perche' non usi la formwidth() int TPrinter::calc_num_cols() const { int numcols; xvt_print_open(); xvt_print_start_thread(calc_cols_callback, (long)&numcols); xvt_print_close(); return numcols; }