This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-goldedplus/golded3/geview.cpp

653 lines
18 KiB
C++

// ------------------------------------------------------------------
// GoldED+
// Copyright (C) 1990-1999 Odinn Sorensen
// Copyright (C) 1999-2000 Alexander S. Aganichev
// ------------------------------------------------------------------
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307 USA
// ------------------------------------------------------------------
// $Id$
// ------------------------------------------------------------------
// Message viewer class implementation.
// ------------------------------------------------------------------
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <malloc.h>
#endif
#include <golded.h>
#include <gutlos.h>
// ------------------------------------------------------------------
GMsgHeaderView::GMsgHeaderView() {
alive = false;
at_row = at_column = width = height = 0;
border_type = gwindow::bordertype_none;
window_color = from_color = to_color = subject_color = BLUE|_LGREY;
title_color = highlight_color = RED|_LGREY;
border_color = YELLOW|_LGREY;
}
// ------------------------------------------------------------------
GMsgHeaderView::~GMsgHeaderView() {
Destroy();
}
// ------------------------------------------------------------------
void GMsgHeaderView::Create() {
alive = true;
window.openxy(
at_row,
at_column,
height,
width,
border_type,
border_color,
window_color
);
}
// ------------------------------------------------------------------
void GMsgHeaderView::Destroy() {
if(alive)
window.close();
else
alive = false;
}
// ------------------------------------------------------------------
void GMsgHeaderView::Use(Area *areaptr, GMsg *msgptr) {
area = areaptr;
msg = msgptr;
}
// ------------------------------------------------------------------
void GMsgHeaderView::Paint() {
ISub buf;
int namewidth = CFG->disphdrnodeset.pos - CFG->disphdrnameset.pos;
int nodewidth = CFG->disphdrdateset.pos - CFG->disphdrnodeset.pos;
int datewidth = MinV(width - CFG->disphdrdateset.pos, CFG->disphdrdateset.len);
#if defined(GUTLOS_FUNCS)
g_set_ostitle_name(struplow(strtmp(area->echoid())), 0);
#endif
// Generate top line fields
char buf1[16];
if((CFG->dispareano == ALWAYS) or (CFG->dispareano and area->board()))
sprintf(buf1, "[%u] ", area->board());
else
*buf1 = NUL;
#if defined(_MSC_VER) || defined(__MINGW32__)
char *top = (char*)alloca(width+1);
#else
__extension__ char top[width+1];
#endif
strxmerge(top, width+1, " ", buf1, strtrim(strtmp(area->desc())), " (",
area->isinternet() ? area->Internetaddress() : area->Aka().addr.make_string(buf),
") ", NULL);
int desclen = strlen(top);
window.printc(0, 0, border_color|ACSET, _box_table(W_BHEAD, 1));
window.prints(0, 1, title_color, top);
if(msg->areakludgeid)
strxmerge(top, width+1, " ", area->echoid(), " (", msg->areakludgeid, ") ", NULL);
else
strxmerge(top, width+1, " ", area->echoid(), " ", NULL);
int taglen = strlen(top);
if((width - (desclen + taglen + 2)) > 0)
window.fill(0, desclen+1, 0, width-(taglen+1)-1, _box_table(W_BHEAD, 1), border_color|ACSET);
window.prints(0, width-taglen-1, title_color, top);
window.printc(0, width-1, border_color|ACSET, _box_table(W_BHEAD, 1));
// Generate message attributes string
bool attrsgenerated = false;
MakeAttrStr(buf, width-CFG->disphdrnodeset.pos, &msg->attr);
if(*buf) {
attrsgenerated = true;
strsetsz(buf, width-CFG->disphdrnodeset.pos);
window.prints(1, CFG->disphdrnodeset.pos, window_color, buf);
}
// Generate message number and reply links string
char* ptr = buf;
int list_max = msg->link.list_max();
ulong* replies = (ulong*)throw_calloc(list_max+1, sizeof(ulong));
ulong replyto, replynext;
if(CFG->switches.get(disprealmsgno)) {
ptr += sprintf(ptr, " %-5.5s: #%lu [%u]", LNG->Msg, msg->msgno, area->Msgn.Count()+(msg->attr.nwm() ? 1 : 0));
replyto = msg->link.to();
replies[0] = msg->link.first();
replynext = msg->link.next();
for(int replyn=1; replyn<list_max+1; replyn++)
replies[replyn] = msg->link.list(replyn-1);
}
else {
uint active = area->Msgn.Count() + (msg->attr.nwm() ? 1 : 0);
ptr += sprintf(ptr, " %-5.5s: %u %s %u", LNG->Msg, msg->attr.nwm() ? active : area->Msgn.ToReln(msg->msgno), LNG->of, active);
replyto = area->Msgn.ToReln(msg->link.to());
replies[0] = area->Msgn.ToReln(msg->link.first());
replynext = area->Msgn.ToReln(msg->link.next());
for(int replyn=1; replyn<list_max+1; replyn++)
replies[replyn] = area->Msgn.ToReln(msg->link.list(replyn-1));
}
if(replyto)
ptr += sprintf(ptr, " -%lu", replyto);
for(int replyn=0,plus=0; (replyn<(list_max+1)) and (not attrsgenerated or ((ptr-buf)<CFG->disphdrnodeset.pos)); replyn++)
if(replies[replyn])
ptr += sprintf(ptr, " %s%lu", (plus++?"":"+"), replies[replyn]);
if(replynext and (not attrsgenerated or ((ptr-buf)<CFG->disphdrnodeset.pos)))
sprintf(ptr, " *%lu", replynext);
throw_free(replies);
strsetsz(buf, attrsgenerated ? CFG->disphdrnodeset.pos : width);
window.prints(1, 0, window_color, buf);
// Get marks
if(area->bookmark == msg->msgno)
window.prints(1, 5, highlight_color, "\x11");
if(area->Mark.Count() and area->Mark.Find(msg->msgno))
window.prints(1, 7, highlight_color, "\x10");
// Generate from info
bool nodegenerated = false;
if(not area->isinternet()) {
if(area->isecho() or not (*msg->ifrom and (*msg->realby or *msg->iorig))) {
// Generate orig node data
if(msg->orig.net)
msg->orig.make_string(buf);
else
*buf = NUL;
nodegenerated = true;
strsetsz(buf, nodewidth);
window.prints(2, CFG->disphdrnodeset.pos, from_color, buf);
}
}
if((not area->isecho() or area->isnewsgroup()) and *msg->ifrom and *msg->realby)
strxmerge(buf, (namewidth+nodewidth), msg->realby, " <", msg->iorig, ">", NULL);
else if((not area->isecho() or area->isnewsgroup()) and *msg->ifrom and *msg->iorig)
strxcpy(buf, msg->iorig, (namewidth+nodewidth));
else
strxcpy(buf, msg->By(), (namewidth+nodewidth));
strsetsz(buf, nodegenerated ? namewidth : (namewidth+nodewidth));
window.prints(2, 0, window_color, LNG->From);
window.prints(2, CFG->disphdrnameset.pos, ((msg->foundwhere&GFIND_FROM) or msg->attr.fmu() or (msg->attr.loc() and CFG->switches.get(displocalhigh))) ? highlight_color : from_color, buf);
if(datewidth > 0) {
if(msg->written)
strftimei(buf, datewidth, LNG->DateTimeFmt, gmtime(&msg->written));
else
*buf = NUL;
strsetsz(buf, datewidth);
window.prints(2, CFG->disphdrdateset.pos, from_color, buf);
}
// Generate dest node data
nodegenerated = false;
if(not area->isinternet()) {
if(not (*msg->ito and (*msg->realto or *msg->idest))) {
if(msg->dest.net and area->isnet()) {
msg->dest.make_string(buf);
if(msg->odest.net) {
if((msg->odest.net != msg->dest.net) or (msg->odest.node != msg->dest.node)) {
sprintf(buf+strlen(buf), " %s %u/%u", LNG->Via, msg->odest.net, msg->odest.node);
}
}
nodegenerated = true;
strsetsz(buf, nodewidth);
window.prints(3, CFG->disphdrnodeset.pos, to_color, buf);
}
}
}
if((not area->isecho() or area->isnewsgroup()) and *msg->ito and *msg->realto)
strxmerge(buf, (namewidth+nodewidth), msg->realto, " <", msg->idest, ">", NULL);
else if((not area->isecho() or area->isnewsgroup()) and *msg->ito and *msg->idest)
strxcpy(buf, msg->idest, (namewidth+nodewidth));
else
strxcpy(buf, msg->To(), (namewidth+nodewidth));
strsetsz(buf, nodegenerated ? namewidth : (namewidth+nodewidth));
window.prints(3, 0, window_color, LNG->To);
window.prints(3, CFG->disphdrnameset.pos, ((msg->foundwhere&GFIND_TO) or msg->attr.tou()) ? highlight_color : to_color, buf);
if(datewidth > 0) {
if(msg->arrived)
strftimei(buf, datewidth, LNG->DateTimeFmt, gmtime(&msg->arrived));
else
*buf = NUL;
strsetsz(buf, datewidth);
window.prints(3, CFG->disphdrdateset.pos, to_color, buf);
}
// Generate subjectline
strxcpy(buf, (msg->attr.att() or msg->attr.frq() or msg->attr.urq()) ? LNG->File : LNG->Subj, 10);
int lngsubjlen = strlen(buf);
window.prints(4, 0, window_color, buf);
strxcpy(buf, msg->re, width-lngsubjlen);
strsetsz(buf, width-lngsubjlen);
window.prints(4, lngsubjlen, (msg->foundwhere&GFIND_SUBJECT) ? highlight_color : subject_color, buf);
// Generate bottom line
window.fill(5, 0, 5, width-1, _box_table(W_BHEAD, 1), border_color|ACSET);
// Calculate attach file sizes
if(msg->attr.att()) {
if(CFG->dispattachsize) {
char buf2[GMAXPATH];
int begpos = strlen(LNG->File);
strcpy(buf, msg->re);
char* ptr = strtok(buf, " ");
while(ptr) {
if(*ptr == '^')
ptr++;
if((isalpha(*ptr) and (ptr[1] == ':')) or (ptr[0] == '\\') or (ptr[0] == '/'))
strcpy(buf2, ptr);
else
sprintf(buf2, "%s%s", CFG->inboundpath, ptr);
long sz = GetFilesize(MapPath(buf2));
if(sz == -1)
sprintf(buf1, " %s ", LNG->n_a);
else {
switch(CFG->dispattachsize) {
case ATTACH_BYTES:
sprintf(buf1, " %li ", sz);
break;
case ATTACH_KBYTES:
sprintf(buf1, " %lik ", (sz+512L)/1024L);
break;
}
}
window.prints(5, begpos+int(ptr-buf)-1, title_color, buf1);
ptr = strtok(NULL, " ");
}
}
}
if(CFG->dispmsgsize and msg->txt and not _in_editor) {
uint len = strlen(msg->txt);
switch(CFG->dispmsgsize) {
case DISPMSGSIZE_BYTES:
sprintf(buf1, "%u", len);
break;
case DISPMSGSIZE_KBYTES:
sprintf(buf1, "%uk", (len+512)/1024);
break;
case DISPMSGSIZE_LINES:
sprintf(buf1, "%u", msg->lines);
break;
default:
*buf1 = NUL;
}
if(*buf1)
window.prints(5, 1, title_color, buf1);
}
}
// ------------------------------------------------------------------
GMsgBodyView::GMsgBodyView() {
alive = false;
scrollbar_visible = false;
at_row = at_column = width = height = visible_width = 0;
border_type = gwindow::bordertype_none;
window_color = BLACK|_LGREY;
highlight_color = WHITE|_RED;
scrollbar_color = DGREY|_LGREY;
border_color = YELLOW|_LGREY;
}
// ------------------------------------------------------------------
GMsgBodyView::~GMsgBodyView() {
Destroy();
}
// ------------------------------------------------------------------
void GMsgBodyView::Create() {
alive = true;
window.openxy(
at_row,
at_column,
height,
width,
border_type,
border_color,
window_color,
scrollbar_color
);
dummy_line.txt = "";
dummy_line.type = 0;
dummy_line.color = window_color;
visible_width = width - (CFG->switches.get(disppagebar) ? 1 : 0);
}
// ------------------------------------------------------------------
void GMsgBodyView::Destroy() {
if(alive)
window.close();
else
alive = false;
}
// ------------------------------------------------------------------
void GMsgBodyView::Use(Area *areaptr, GMsg *msgptr, int startline) {
area = areaptr;
msg = msgptr;
// Find the first highlighted line and go to it
if(msg->foundwhere & GFIND_BODY) {
for(startline=0; startline<msg->lines; startline++) {
if(msg->line[startline]->type & GLINE_HIGH)
break;
}
// Adjust position in window
startline -= height / 3;
if(startline < 0)
startline = 0;
else if((startline + height - 1) >= msg->lines)
startline = msg->lines - height;
}
if(startline >= msg->lines)
startline = msg->lines - 1;
if(startline < 0)
startline = 0;
upperline = startline;
lowerline = upperline + height - 1;
can_pagedown = lowerline < (msg->lines-1);
scrollbar_visible = CFG->switches.get(disppagebar) ? (msg->lines > height) : false;
visible_width = scrollbar_visible ? width-1 : width;
window.set_scrollbar_color(scrollbar_visible ? scrollbar_color : -1);
}
// ------------------------------------------------------------------
void GMsgBodyView::PaintLine(int row, Line *line) {
// Calculate effective coordinates for vputs
int vrow = gwin.active->srow + row;
uint llen = line->txt.length();
int color = (line->type & GLINE_HIGH) ? highlight_color : line->color;
// Trim line if it longer than should be. This actually happens in very rare
// cases, but always when hex dump displayed.
if(llen > visible_width) {
llen = visible_width;
line->txt.erase(llen);
}
// Print it
if(not SearchHighlight(line, vrow, visible_width, highlight_color)) {
if(line->type & GLINE_ORIG and strneql(line->txt.c_str(), " * Origin: ", 11)) {
vputs(vrow, 0, color, " * Origin: ");
StyleCodeHighlight(line->txt.c_str()+11, vrow, 11, not AA->attr().hex() and CFG->hidestylies, color);
}
else
StyleCodeHighlight(line->txt.c_str(), vrow, 0, not AA->attr().hex() and CFG->hidestylies, color);
int tlen = strlen(line->txt.c_str());
vputns(vrow, tlen, color, "", visible_width-tlen);
}
else
vputns(vrow, 0, color, line->txt.c_str(), visible_width);
}
// ------------------------------------------------------------------
void GMsgBodyView::Paint() {
window.activate_quick();
Line* dummy_index = NULL;
Line** line_index = msg->line ? (msg->line + upperline) : &dummy_index;
for(int row=0; row<height; row++)
PaintLine(row, *line_index ? *line_index++ : &dummy_line);
UpdateScrollbar();
}
// ------------------------------------------------------------------
int GMsgBodyView::Top(int redraw) {
if(redraw or (msg->lines > height)) {
can_pagedown = true;
upperline = 0;
lowerline = height - 1;
Paint();
return true;
}
return false;
}
// ------------------------------------------------------------------
int GMsgBodyView::Bottom() {
if(msg->lines > height) {
if(msg->lines <= height) {
can_pagedown = true;
upperline = 0;
}
else {
can_pagedown = false;
upperline = msg->lines - height;
}
lowerline = upperline + height - 1;
Paint();
return true;
}
return false;
}
// ------------------------------------------------------------------
int GMsgBodyView::PageUp() {
if(msg->lines > height) {
can_pagedown = true;
if(upperline) {
upperline -= height - 1;
if(upperline < 0)
upperline = 0;
lowerline = upperline + height - 1;
Paint();
return true;
}
}
return false;
}
// ------------------------------------------------------------------
int GMsgBodyView::PageDown() {
if(msg->lines > height) {
if(can_pagedown) {
if(lowerline < msg->lines-1) {
lowerline += height - 1;
if(lowerline >= msg->lines-1)
can_pagedown = false;
upperline = lowerline - height + 1;
Paint();
return true;
}
}
}
return false;
}
// ------------------------------------------------------------------
int GMsgBodyView::LineUp() {
if(msg->lines > height) {
if(upperline) {
window.scroll_down();
upperline--;
lowerline--;
#ifdef GOLD_MOUSE
gmou.HideCursor();
#endif
PaintLine(0, msg->line[upperline]);
#ifdef GOLD_MOUSE
gmou.ShowCursor();
#endif
can_pagedown = lowerline < (msg->lines-1);
UpdateScrollbar();
return true;
}
}
return false;
}
// ------------------------------------------------------------------
int GMsgBodyView::LineDown() {
if(msg->lines > height) {
if(lowerline < (msg->lines-1)) {
window.scroll_up();
upperline++;
lowerline++;
#ifdef GOLD_MOUSE
gmou.HideCursor();
#endif
PaintLine(height-1, msg->line[lowerline]);
#ifdef GOLD_MOUSE
gmou.ShowCursor();
#endif
can_pagedown = lowerline < (msg->lines-1);
UpdateScrollbar();
return true;
}
}
return false;
}
// ------------------------------------------------------------------
int GMsgBodyView::Continue() {
if(can_pagedown)
return PageDown();
return false;
}
// ------------------------------------------------------------------
int GMsgBodyView::ThumbTrack(int pos) {
return ThumbPosition(pos);
}
// ------------------------------------------------------------------
int GMsgBodyView::ThumbPosition(int pos) {
upperline = pos;
lowerline = upperline + height - 1;
can_pagedown = lowerline < (msg->lines-1);
Paint();
return true;
}
// ------------------------------------------------------------------
void GMsgBodyView::UpdateScrollbar() {
if(CFG->switches.get(disppagebar) and scrollbar_visible)
window.vscrollbar(msg->lines, msg->lines-height, upperline);
}
// ------------------------------------------------------------------
void GMsgBodyView::prints(int wrow, int wcol, int atr, const char* str) {
vputs(wrow, wcol, atr, str);
}
// ------------------------------------------------------------------