1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518 |
- /*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is Vision.
- *
- * The Initial Developer of the Original Code is The Vision Team.
- * Portions created by The Vision Team are
- * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights
- * Reserved.
- *
- * Contributor(s): Rene Gollent
- * Todd Lair
- * Alan Ellis <alan@cgsoftware.org>
- */
- #define FORE_WHICH 0
- #define BACK_WHICH 1
- #define FONT_WHICH 2
- #define MARGIN_WIDTH 10.0
- #define MARGIN_INDENT 10.0
- #define OFFVIEW_TIMER (10000LL)
- #define ABS(x) (x * ((x<0) ? -1 : 1))
- #define SOFTBREAK_STEP 5
- #include <string.h>
- #include <stdio.h>
- #include <time.h>
- #include <ctype.h>
- #include <assert.h>
- #include <Message.h>
- #include <Messenger.h>
- #include <MessageRunner.h>
- #include <PopUpMenu.h>
- #include <MenuItem.h>
- #include <Clipboard.h>
- #include <ScrollView.h>
- #include <ScrollBar.h>
- #include <Region.h>
- #include <Window.h>
- #include <Bitmap.h>
- #include <Cursor.h>
- #include "ObjectList.h"
- #include "Theme.h"
- #include "RunView.h"
- #include "URLCrunch.h"
- #include "Vision.h"
- #include "Utilities.h"
- // cursor data for hovering over URLs
- static unsigned char URLCursorData[] = {16,1,2,2,
- 0,0,0,0,56,0,36,0,36,0,19,224,18,92,9,42,
- 8,1,60,33,76,49,66,121,48,125,12,253,2,0,1,0,
- 0,0,0,0,56,0,60,0,60,0,31,224,31,252,15,254,
- 15,255,63,255,127,255,127,255,63,255,15,255,3,254,1,248
- };
- struct SoftBreak
- {
- int16 fOffset;
- float fHeight;
- float fAscent;
- };
- struct URL
- {
- int32 fOffset;
- int32 fLength;
- BString fUrl;
- URL (const char *address, int32 off, int32 len) :
- fOffset (off),
- fLength (len),
- fUrl (address)
- { }
- };
- typedef BObjectList<URL> urllist;
- struct SoftBreakEnd
- {
- int16 fOffset;
- SoftBreakEnd (int16 offset)
- : fOffset (offset)
- { }
- };
- struct FontColor
- {
- int16 fOffset;
- // G++ is stupid. We only need 2 bits
- // for fWhich, but the compiler has a bug
- // and warns us against fWhich == 2
- int16 fWhich : 3;
- int16 fIndex : 13;
- };
- struct Line
- {
- char *fText;
- time_t fStamp;
- urllist *fUrls;
- int16 *fSpaces;
- int16 *fEdges;
- FontColor *fFcs;
- SoftBreak *fSofties;
- float fTop;
- float fBottom;
- int16 fLength;
- int16 fSpace_count;
- int16 fEdge_count;
- int16 fFc_count;
- int16 fSoftie_size;
- int16 fSoftie_used;
- Line (
- const char *buffer,
- int16 fLength,
- float top,
- float width,
- Theme *fTheme,
- const char *fStamp_format,
- int16 fore,
- int16 back,
- int16 font);
- ~Line (void);
- void Append (
- const char *buffer,
- int16 len,
- float width,
- Theme *fTheme,
- int16 fore,
- int16 back,
- int16 font);
- void FigureSpaces (void);
- void FigureFontColors (
- int16 pos,
- int16 fore,
- int16 back,
- int16 font);
- void FigureEdges (
- Theme *fTheme,
- float width);
- void SoftBreaks (
- Theme * fTheme,
- float width);
- void AddSoftBreak (SoftBreakEnd , float &,
- uint16 &, int16 &, float &, float &, Theme *);
- int16 CountChars (int16 pos, int16 len);
- size_t SetStamp (const char *, bool);
- void SelectWord (int16 *, int16 *);
- };
- inline int32
- UTF8_CHAR_LEN (uchar c)
- {
- return (((0xE5000000 >> (((c) >> 3) & 0x1E)) & 3) + 1);
- }
- RunView::RunView (
- BRect frame,
- const char *name,
- Theme *theme,
- uint32 resizingMode,
- uint32 flags)
- : BView (
- frame,
- name,
- resizingMode,
- flags | B_WILL_DRAW | B_FRAME_EVENTS),
- fScroller (NULL),
- fTheme (theme),
- fWorking (NULL),
- fLine_count (0),
- fStamp_format (NULL),
- fClipping_name (NULL),
- fSp_start (0, 0),
- fSp_end (0, 0),
- fTracking (0),
- fTrack_offset (0, 0),
- fOff_view_runner (NULL),
- fOff_view_time (0),
- fResizedirty (false),
- fFontsdirty (false),
- fMyPopUp (NULL),
- fLastClick (0,0),
- fLastClickTime (0)
- {
- memset (fLines, 0, sizeof (fLines));
- fURLCursor = new BCursor (URLCursorData);
- fTheme->ReadLock();
- BView::SetViewColor (B_TRANSPARENT_COLOR);
- BView::SetLowColor (fTheme->BackgroundAt (Theme::NormalBack));
- BView::SetHighColor (fTheme->ForegroundAt (Theme::NormalFore));
- fTheme->ReadUnlock();
- }
- RunView::~RunView (void)
- {
- for (int16 i = 0; i < fLine_count; ++i)
- delete fLines[i];
- delete fWorking;
- delete fURLCursor;
- delete [] fStamp_format;
- delete [] fClipping_name;
- }
- void
- RunView::AttachedToWindow (void)
- {
- BView::AttachedToWindow();
- #if B_BEOS_VERSION_DANO
- SetDoubleBuffering (B_UPDATE_INVALIDATED | B_UPDATE_SCROLLED | B_UPDATE_EXPOSED | B_UPDATE_RESIZED);
- #endif
- RecalcScrollBar (false);
- fTheme->WriteLock();
- fTheme->AddView (this);
- fTheme->WriteUnlock();
- }
- void
- RunView::DetachedFromWindow (void)
- {
- fTheme->WriteLock();
- fTheme->RemoveView (this);
- fTheme->WriteUnlock();
- }
- void
- RunView::FrameResized (float start_width, float height)
- {
- BView::FrameResized (start_width, height);
- if (IsHidden())
- {
- fResizedirty = true;
- return;
- }
- ResizeRecalc();
- }
- void
- RunView::TargetedByScrollView (BScrollView *s)
- {
- fScroller = s;
- BView::TargetedByScrollView (fScroller);
- }
- void
- RunView::Show (void)
- {
- if (fFontsdirty)
- {
- FontChangeRecalc();
- // this effectively does the same thing as resize so if both have changed, only
- // do the fonts recalculation
- fFontsdirty = false;
- fResizedirty = false;
- }
- else if (fResizedirty)
- {
- ResizeRecalc();
- fResizedirty = false;
- }
- BView::Show();
- }
- void
- RunView::Draw (BRect frame)
- {
- Window()->DisableUpdates();
- Window()->BeginViewTransaction();
- rgb_color low_color, hi_color, view_color, sel_color, sel_fText;
- float height (frame.bottom);
- BRect bounds (Bounds());
- BRegion clipper;
- bool drawSelection (false);
- bool checkSelection (fSp_start != fSp_end);
- clipper.Set (frame);
- ConstrainClippingRegion (&clipper);
- fTheme->ReadLock();
- view_color = fTheme->BackgroundAt (Theme::NormalBack);
- sel_color = fTheme->BackgroundAt (Theme::SelectionBack);
- if (((sel_color.red + sel_color.blue + sel_color.green) / 3) >= 127)
- {
- sel_fText.red = sel_fText.green = sel_fText.blue = 0;
- sel_fText.alpha = 255;
- }
- else
- {
- sel_fText.red = sel_fText.green = sel_fText.blue = sel_fText.alpha = 255;
- }
- BRect remains;
- if (fLine_count == 0)
- remains = frame;
- else if (frame.bottom >= fLines[fLine_count - 1]->fBottom + 1.0)
- remains.Set (
- frame.left,
- fLines[fLine_count - 1]->fBottom + 1.0,
- frame.right,
- frame.bottom);
- if (remains.IsValid())
- {
- SetLowColor (view_color);
- FillRect (remains, B_SOLID_LOW);
- }
- for (int16 i = fLine_count - 1; i >= 0; --i)
- {
- Line *line (fLines[i]);
- if (line->fBottom < frame.top)
- break;
- BRect r (bounds.left, line->fTop, bounds.right, line->fBottom);
- if (!frame.Intersects (r))
- continue;
- float indent (ceil (MARGIN_WIDTH / 2.0));
- int16 place (0);
- int16 fore (0);
- int16 back (0);
- int16 font (0);
- height = line->fTop;
- for (int16 sit = 0; sit < line->fSoftie_used; ++sit)
- {
- int16 last_len (UTF8_CHAR_LEN (line->fText[line->fSofties[sit].fOffset]));
- float left (indent);
- float start (0.0);
- // Fill indentation
- SetLowColor (view_color);
- SetDrawingMode (B_OP_COPY);
- r.Set (0.0, height, indent - 1.0, height + line->fSofties[sit].fHeight - 1.0);
- FillRect (r, B_SOLID_LOW);
- if (sit)
- {
- int16 j (place);
- while (--j >= 0)
- if ((start = line->fEdges[j]) != 0)
- break;
- }
- while (place < line->fSofties[sit].fOffset + last_len)
- {
- // Get current foreground color and set
- while (fore < line->fFc_count)
- {
- if (line->fFcs[fore].fWhich == FORE_WHICH)
- {
- if (line->fFcs[fore].fOffset > place)
- break;
- hi_color = fTheme->ForegroundAt (line->fFcs[fore].fIndex);
- }
- ++fore;
- }
- // Get current background color and set
- while (back < line->fFc_count)
- {
- if (line->fFcs[back].fWhich == BACK_WHICH)
- {
- if (line->fFcs[back].fOffset > place)
- break;
- low_color = fTheme->BackgroundAt (line->fFcs[back].fIndex);
- }
- ++back;
- }
- // Get current font and set
- while (font < line->fFc_count)
- {
- if (line->fFcs[font].fWhich == FONT_WHICH)
- {
- if (line->fFcs[font].fOffset > place)
- break;
- const BFont &f (fTheme->FontAt (line->fFcs[font].fIndex));
- SetFont (&f);
- }
- ++font;
- }
- int16 fLength (line->fSofties[sit].fOffset - place + last_len);
- if (fore < line->fFc_count
- && line->fFcs[fore].fOffset - place < fLength)
- fLength = line->fFcs[fore].fOffset - place;
- if (back < line->fFc_count
- && line->fFcs[back].fOffset - place < fLength)
- fLength = line->fFcs[back].fOffset - place;
- if (font < line->fFc_count
- && line->fFcs[font].fOffset - place < fLength)
- fLength = line->fFcs[font].fOffset - place;
- if (checkSelection)
- {
- // case 1: current line marks beginning of selection
- if (i == fSp_start.fLine)
- {
- // if we're just prior to the selection, clip fLength to only
- // draw up to the selection start
- if (place + fLength >= fSp_start.fOffset && place < fSp_start.fOffset)
- {
- fLength = fSp_start.fOffset - place;
- drawSelection = false;
- }
- // we're at the selection, switch drawing color mode
- else if (place >= fSp_start.fOffset)
- {
- if (fSp_end.fLine == fSp_start.fLine)
- {
- if (place < fSp_end.fOffset)
- {
- drawSelection = true;
- if ((fSp_end.fOffset - place) < fLength)
- fLength = fSp_end.fOffset - place;
- }
- else
- drawSelection = false;
- }
- else
- drawSelection = true;
- }
- else
- drawSelection = false;
- }
- // case 2: line in between beginning and end of selection,
- // highlight entire line
- else if (i > fSp_start.fLine && i < fSp_end.fLine)
- drawSelection = true;
- // case 3: last line of selection, with multiple fLines in between
- else if (i == fSp_end.fLine && i != fSp_start.fLine)
- {
- if (place < (fSp_end.fOffset))
- {
- if (fSp_end.fOffset - place < fLength)
- fLength = (fSp_end.fOffset - place);
- drawSelection = true;
- }
- else
- drawSelection = false;
- }
- else
- drawSelection = false;
- }
- if (place + fLength == line->fLength)
- --fLength;
- int16 k (place + fLength - 1);
- while (line->fEdges[k] == 0)
- --k;
- r.Set (
- left,
- height,
- line->fEdges[k] + indent - start,
- height + line->fSofties[sit].fHeight - 1.0);
- SetDrawingMode (B_OP_COPY);
- if (drawSelection)
- SetLowColor (sel_color);
- else
- SetLowColor (low_color);
- SetHighColor (hi_color);
- FillRect (r, B_SOLID_LOW);
- if (drawSelection)
- SetHighColor (sel_fText);
- SetDrawingMode (B_OP_OVER);
- DrawString (
- line->fText + place,
- min_c (fLength, line->fLength - place - 1),
- BPoint (left, height + line->fSofties[sit].fAscent));
- left = line->fEdges[k] + indent - start;
- if ((place += fLength) + 1 >= line->fLength)
- ++place;
- }
- // Margin after fText
- SetDrawingMode (B_OP_COPY);
- SetLowColor (view_color);
- FillRect (
- BRect (
- left + 1.0,
- height,
- bounds.right,
- height + line->fSofties[sit].fHeight - 1.0),
- B_SOLID_LOW);
- height += line->fSofties[sit].fHeight;
- if (sit == 0)
- indent += (MARGIN_INDENT / 2.0);
- }
- }
- fTheme->ReadUnlock();
- Window()->EndViewTransaction();
- Window()->EnableUpdates();
- ConstrainClippingRegion (NULL);
- }
- void
- RunView::SetViewColor (rgb_color color)
- {
- assert (memcmp (&color, &B_TRANSPARENT_COLOR, sizeof (rgb_color)) != 0);
- BView::SetViewColor (color);
- }
- void
- RunView::BuildPopUp (void)
- {
- // This function checks certain criteria (fText is selected,
- // TextView is editable, etc) to determine fWhich MenuItems
- // to enable and disable
- bool enablecopy (true),
- enableselectall (true),
- enablelookup (false);
- BString querystring ("");
- if (fSp_start == fSp_end)
- enablecopy = false; // no selection
- if (!fLine_count)
- enableselectall = false;
- if (enablecopy)
- {
- enablelookup = true; // has a selection less than 32 chars long
- GetSelectionText(querystring);
- }
- fMyPopUp = new BPopUpMenu ("IRCView Context Menu", false, false);
- BMenuItem *item;
- BMessage *lookup;
- lookup = new BMessage (M_LOOKUP_WEBSTER);
- lookup->AddString ("string", querystring);
- item = new BMenuItem("Lookup (dictionary)", lookup);
- item->SetEnabled (enablelookup);
- item->SetTarget (Parent());
- fMyPopUp->AddItem (item);
- lookup = new BMessage (M_LOOKUP_GOOGLE);
- lookup->AddString ("string", querystring);
- item = new BMenuItem("Lookup (Google)", lookup);
- item->SetEnabled (enablelookup);
- item->SetTarget (Parent());
- fMyPopUp->AddItem (item);
-
- lookup = new BMessage (M_LOOKUP_ACRONYM);
- lookup->AddString ("string", querystring);
- item = new BMenuItem("Lookup (acronym finder)", lookup);
- item->SetEnabled (enablelookup);
- item->SetTarget (Parent());
- fMyPopUp->AddItem (item);
- fMyPopUp->AddSeparatorItem();
-
- item = new BMenuItem("Copy", new BMessage (B_COPY), 'C');
- item->SetEnabled (enablecopy);
- item->SetTarget (this);
- fMyPopUp->AddItem (item);
- item = new BMenuItem("Select all", new BMessage (B_SELECT_ALL), 'A');
- item->SetEnabled (enableselectall);
- item->SetTarget (this);
- fMyPopUp->AddItem (item);
- fMyPopUp->SetFont (be_plain_font);
- }
- bool
- RunView::CheckClickBounds (const SelectPos &s, const BPoint &point) const
- {
- return ((point.x <= fLines[s.fLine]->fEdges[fLines[s.fLine]->fLength - 1])
- && (point.y <= fLines[s.fLine]->fBottom));
- }
- void
- RunView::MouseDown (BPoint point)
- {
- if (!fLine_count)
- return;
- BMessage *msg (Window()->CurrentMessage());
- uint32 buttons;
- uint32 mouseModifiers;
- bigtime_t sysTime;
- msg->FindInt64 ("when", &sysTime);
- uint16 clicks = CheckClickCount (point, fLastClick, sysTime, fLastClickTime, fClickCount) % 3;
- msg->FindInt32 ("buttons", reinterpret_cast<int32 *>(&buttons));
- msg->FindInt32 ("modifiers", reinterpret_cast<int32 *>(&mouseModifiers));
- SelectPos s (PositionAt (point));
- bool inBounds (CheckClickBounds (s, point));
- if (buttons == B_SECONDARY_MOUSE_BUTTON
- && (mouseModifiers & B_SHIFT_KEY) == 0
- && (mouseModifiers & B_COMMAND_KEY) == 0
- && (mouseModifiers & B_CONTROL_KEY) == 0
- && (mouseModifiers & B_OPTION_KEY) == 0
- && (mouseModifiers & B_MENU_KEY) == 0)
- {
- SelectPos start (s),
- end (s);
- // select word
- if (inBounds && !IntersectSelection (s,s))
- {
- fLines[s.fLine]->SelectWord (&start.fOffset, &end.fOffset);
- Select (start, end);
- }
- BuildPopUp();
- fMyPopUp->Go (
- ConvertToScreen (point),
- true,
- false);
- delete fMyPopUp;
- fMyPopUp = 0;
- return;
- }
- if (buttons == B_PRIMARY_MOUSE_BUTTON
- && (mouseModifiers & B_SHIFT_KEY) == 0
- && (mouseModifiers & B_COMMAND_KEY) == 0
- && (mouseModifiers & B_CONTROL_KEY) == 0
- && (mouseModifiers & B_OPTION_KEY) == 0
- && (mouseModifiers & B_MENU_KEY) == 0)
- {
- SelectPos start (s),
- end (s);
- switch (clicks)
- {
- case 2:
- {
- if (inBounds)
- {
- // select word
- fLines[s.fLine]->SelectWord (&start.fOffset, &end.fOffset);
- Select (start, end);
- return;
- }
- }
- break;
- case 0:
- {
- if (inBounds)
- {
- start.fOffset = 0;
- end.fOffset = fLines[s.fLine]->fLength - 1;
- Select (start, end);
- return;
- }
- }
- break;
- default:
- {
- if (!inBounds || !IntersectSelection (s, s))
- Select (s,s);
- SetMouseEventMask (B_POINTER_EVENTS);
- fTracking = 1;
- fTrack_offset = s;
- return;
- }
- }
- }
- else if (buttons == B_PRIMARY_MOUSE_BUTTON
- && (mouseModifiers & B_SHIFT_KEY) != 0
- && (mouseModifiers & B_COMMAND_KEY) == 0
- && (mouseModifiers & B_CONTROL_KEY) == 0
- && (mouseModifiers & B_OPTION_KEY) == 0
- && (mouseModifiers & B_MENU_KEY) == 0)
- {
- if (s.fLine < fSp_start.fLine || s.fOffset < fSp_start.fOffset)
- {
- Select (s, fSp_end);
- fTrack_offset = SelectPos (fSp_end.fLine, (fSp_end.fOffset > 0) ? fSp_end.fOffset - 1 : fSp_end.fOffset);
- }
- else
- {
- Select (fSp_start, s);
- fTrack_offset = fSp_start;
- }
- SetMouseEventMask (B_POINTER_EVENTS);
- fTracking = 2;
- }
- }
- void
- RunView::CheckURLCursor (BPoint point)
- {
- if (!fLine_count)
- return;
- SelectPos s = PositionAt (point);
- if (!fLines[s.fLine]->fUrls)
- {
- // if there aren't any URLs in the current line, go back to default
- SetViewCursor (B_CURSOR_SYSTEM_DEFAULT);
- return;
- }
- Line *curline (fLines[s.fLine]);
- for (int32 i = 0; i < curline->fUrls->CountItems(); i++)
- {
- URL *current = curline->fUrls->ItemAt(i);
- if ((s.fOffset >= current->fOffset)
- && (s.fOffset <= current->fOffset + current->fLength))
- {
- SetViewCursor (fURLCursor);
- return;
- }
- }
- // no URLs found, set back to default
- SetViewCursor (B_CURSOR_SYSTEM_DEFAULT);
- }
- void
- RunView::MouseMoved (BPoint point, uint32 transit, const BMessage *msg)
- {
- if (fTracking == 0
- && fLine_count
- && (transit == B_ENTERED_VIEW
- || transit == B_INSIDE_VIEW))
- CheckURLCursor (point);
- if (!fLine_count || fTracking == 0)
- {
- BView::MouseMoved (point, transit, msg);
- return;
- }
- switch (transit)
- {
- case B_ENTERED_VIEW:
- if (fOff_view_runner)
- {
- delete fOff_view_runner;
- fOff_view_runner = 0;
- }
- if (fTracking == 1 || fTracking == 2)
- ExtendTrackingSelect (point);
- break;
- case B_EXITED_VIEW:
- if (fTracking == 1 || fTracking == 2)
- ShiftTrackingSelect (point, true, OFFVIEW_TIMER);
- break;
- case B_OUTSIDE_VIEW:
- if (fTracking == 1 || fTracking == 2)
- {
- bigtime_t now (system_time());
- ShiftTrackingSelect (
- point,
- false,
- max_c (0LL, min_c (OFFVIEW_TIMER, OFFVIEW_TIMER - (now - fOff_view_time))));
- }
- break;
- case B_INSIDE_VIEW:
- if ((fTracking == 1) && (fSp_start != fSp_end))
- {
- BMessage msg (B_MIME_DATA);
- BString text;
- GetSelectionText (text);
- msg.AddData (
- "text/plain",
- B_MIME_TYPE,
- text.String(),
- text.Length());
- BString clip_name (" Clipping");
- if (fClipping_name)
- clip_name.Prepend (fClipping_name);
- else
- clip_name.Prepend ("RunView");
- msg.AddString ("be:clip_name", clip_name.String());
- msg.AddInt32 ("be:actions", B_COPY_TARGET);
- BRect frame (
- fLines[fSp_start.fLine]->fEdges[fSp_start.fOffset],
- fLines[fSp_start.fLine]->fTop,
- fLines[fSp_end.fLine]->fEdges[fSp_end.fOffset],
- fLines[fSp_end.fLine]->fBottom);
- if (fSp_start.fLine != fSp_end.fLine)
- {
- frame.left = 0.0;
- frame.right = Bounds().right;
- }
- // selection lies within the bounds of a line, check
- // if it fLines on one of the wrapped subfLines and calculate rectangle
- // appropriately
- else
- {
- Line *line (fLines[fSp_start.fLine]);
- float left (line->fEdges[fSp_start.fOffset]),
- top (line->fTop),
- right (line->fEdges[fSp_end.fOffset]),
- bottom (line->fBottom);
- int top_softie (0), bottom_softie (0);
- bool start_found (false);
- bool end_found (false);
- if (line->fSoftie_used)
- {
- if (fSp_start.fOffset < line->fSofties[0].fOffset)
- start_found = true;
- if (fSp_end.fOffset < line->fSofties[0].fOffset)
- end_found = true;
- }
- if (!end_found)
- for (int16 sit = 1; sit < line->fSoftie_used; ++sit)
- {
- if (!start_found && fSp_start.fOffset < line->fSofties[sit].fOffset)
- {
- left = line->fEdges[fSp_start.fOffset] -
- line->fEdges[line->fSofties[sit-1].fOffset];
- top += (sit) * line->fSofties[sit].fHeight;
- top_softie = sit;
- start_found = true;
- }
- if (fSp_end.fOffset < line->fSofties[sit].fOffset)
- {
- right = line->fEdges[fSp_end.fOffset] -
- line->fEdges[line->fSofties[sit-1].fOffset];
- bottom = top + (sit - top_softie + 1) * line->fSofties[sit].fHeight;
- bottom_softie = sit;
- end_found = true;
- break;
- }
- }
- if (!end_found)
- {
- int32 soft_count = (line->fSoftie_used >= 2) ?
- line->fSoftie_used - 2 : 0;
- right = line->fEdges[line->fLength - 1] -
- line->fEdges[line->fSofties[soft_count].fOffset];
- bottom_softie = soft_count - 2;
- }
- if (right < left || (bottom_softie - top_softie) > 0)
- {
- left = 0.0;
- right = Bounds().right;
- }
- frame.Set (left, top, right, bottom);
- frame.OffsetBy (MARGIN_WIDTH / 2.0, 0.0);
- }
- if (frame.Height() > Bounds().Height())
- frame = Bounds();
- DragMessage (&msg, frame);
- fTracking = 3;
- }
- else if (fTracking == 1 || fTracking == 2)
- ExtendTrackingSelect (point);
- break;
- }
- }
- void
- RunView::MouseUp (BPoint point)
- {
- SelectPos s (PositionAt (point));
- bool url_handle (false);
- if (!fLine_count)
- {
- fTracking = 0;
- return;
- }
- if (fTracking == 1)
- {
- Line *curline (fLines[s.fLine]);
- if (curline->fUrls)
- {
- for (int32 i = 0; i < curline->fUrls->CountItems(); i++)
- {
- URL *current = curline->fUrls->ItemAt(i);
- if ((s.fOffset >= current->fOffset)
- && (s.fOffset <= current->fOffset + current->fLength))
- {
- vision_app->LoadURL (current->fUrl.String());
- url_handle = true;
- break;
- }
- }
- }
- if (!url_handle && s == fTrack_offset)
- Select (s, s);
- }
- if (fOff_view_runner)
- {
- delete fOff_view_runner;
- fOff_view_runner = 0;
- }
- fTracking = 0;
- }
- void
- RunView::ExtendTrackingSelect (BPoint point)
- {
- SelectPos s (PositionAt (point));
- if (s.fLine < fTrack_offset.fLine || (s.fLine == fTrack_offset.fLine && s.fOffset < fTrack_offset.fOffset))
- {
- Select (s, fTrack_offset);
- fTracking = 2;
- }
- else if (s.fLine > fTrack_offset.fLine || (s.fLine == fTrack_offset.fLine && s.fOffset > fTrack_offset.fOffset))
- {
- Select (fTrack_offset, s);
- fTracking = 2;
- }
- }
- void
- RunView::ShiftTrackingSelect (BPoint point, bool move, bigtime_t timer)
- {
- BRect bounds (Bounds());
- if (fOff_view_runner)
- {
- delete fOff_view_runner;
- fOff_view_runner = 0;
- }
- if (point.y < bounds.top)
- {
- if (bounds.top > 0.0)
- {
- float delta (bounds.top - point.y);
- if (fOff_view_runner == 0)
- {
- BMessage *msg (new BMessage (M_OFFVIEW_SELECTION));
- msg->AddFloat ("delta", delta);
- msg->AddBool ("bottom", false);
- msg->AddPoint ("point", point);
- fOff_view_runner = new BMessageRunner (
- BMessenger (this),
- msg,
- timer == 0LL ? OFFVIEW_TIMER : timer);
- }
- if (move || timer == 0)
- {
- delta = max_c (ABS (ceil (delta / 2.0)), 10.0);
- delta = min_c (delta, Bounds().Height());
- if (bounds.top - delta < 0.0)
- delta = bounds.top;
- ScrollBy (0.0, -delta);
- fOff_view_time = system_time();
- }
- }
- point.x = 0.0;
- point.y = Bounds().top;
- ExtendTrackingSelect (point);
- }
- if (point.y > bounds.bottom)
- {
- Line *line (fLines[fLine_count-1]);
- if (line
- && line->fBottom > bounds.bottom)
- {
- float delta (point.y - bounds.bottom);
- if (fOff_view_runner == 0)
- {
- BMessage *msg (new BMessage (M_OFFVIEW_SELECTION));
- msg->AddFloat ("delta", delta);
- msg->AddBool ("bottom", true);
- msg->AddPoint ("point", point);
- fOff_view_runner = new BMessageRunner (
- BMessenger (this),
- msg,
- timer == 0LL ? OFFVIEW_TIMER : timer);
- }
- if (move || timer == 0)
- {
- delta = max_c (ABS (ceil (delta / 2.0)), 10.0);
- delta = min_c (delta, Bounds().Height());
- if (bounds.bottom + delta > line->fBottom)
- delta = line->fBottom - bounds.bottom;
- ScrollBy (0.0, delta);
- fOff_view_time = system_time();
- }
- }
- point.x = Bounds().right;
- point.y = Bounds().bottom;
- ExtendTrackingSelect (point);
- }
- else
- ExtendTrackingSelect (point);
- }
- void
- RunView::MessageReceived (BMessage *msg)
- {
- switch (msg->what)
- {
- case M_THEME_FOREGROUND_CHANGE:
- case M_THEME_BACKGROUND_CHANGE:
- if (!IsHidden())
- Invalidate (Bounds());
- break;
- case M_THEME_FONT_CHANGE:
- {
- Theme *save (fTheme);
- fTheme = NULL;
- SetTheme (save);
- break;
- }
- case B_SELECT_ALL:
- SelectAll();
- break;
- case B_COPY:
- if (fSp_start != fSp_end
- && be_clipboard->Lock())
- {
- BString fText;
- GetSelectionText (fText);
- be_clipboard->Clear();
- BMessage *msg (be_clipboard->Data());
- msg->AddData ("text/plain", B_MIME_TYPE, fText.String(), fText.Length());
- be_clipboard->Commit();
- be_clipboard->Unlock();
- }
- break;
- case M_OFFVIEW_SELECTION:
- {
- BPoint point;
- float delta;
- bool bottom;
- msg->FindPoint ("point", &point);
- msg->FindBool ("bottom", &bottom);
- msg->FindFloat ("delta", &delta);
- if (bottom)
- point.y = Bounds().bottom + delta;
- else
- point.y = Bounds().top - delta;
- ShiftTrackingSelect (point, true, OFFVIEW_TIMER);
- break;
- }
- default:
- BView::MessageReceived (msg);
- }
- }
- void
- RunView::ResizeRecalc (void)
- {
- float width (Bounds().Width() - MARGIN_WIDTH);
- int16 fSoftie_size (0), fSoftie_used (0);
- SoftBreak *fSofties (NULL);
- BRect bounds (Bounds());
- BRegion region;
- float top (0.0);
- fTheme->ReadLock();
- for (int16 i = 0; i < fLine_count; ++i)
- {
- float old_top (fLines[i]->fTop), old_bottom (fLines[i]->fBottom);
- if (fSoftie_size < fLines[i]->fSoftie_used)
- {
- delete [] fSofties;
- fSofties = new SoftBreak [fSoftie_size = fLines[i]->fSoftie_size];
- }
- fSoftie_used = fLines[i]->fSoftie_used;
- memcpy (fSofties, fLines[i]->fSofties, (fSoftie_used * sizeof (SoftBreak)));
- fLines[i]->fTop = top;
- fLines[i]->SoftBreaks (fTheme, width);
- top = fLines[i]->fBottom + 1.0;
- BRect r (0.0, fLines[i]->fTop, bounds.right, fLines[i]->fBottom);
- if (bounds.Intersects (r)
- && (old_top != fLines[i]->fTop
- || old_bottom != fLines[i]->fBottom
- || fSoftie_used != fLines[i]->fSoftie_used
- || memcmp (fSofties, fLines[i]->fSofties, fSoftie_used * sizeof (SoftBreak))))
- region.Include (r);
- }
- fTheme->ReadUnlock();
- if (Window())
- {
- if (RecalcScrollBar (true))
- Invalidate (Bounds());
- else
- {
- int32 count (region.CountRects()), j;
- for (j = 0; j < count; ++j)
- Invalidate (region.RectAt (j));
- if (top <= bounds.bottom)
- {
- BRect r (bounds);
- r.top = top;
- Invalidate (r);
- }
- }
- Window()->Sync();
- }
- if (fWorking) fWorking->fTop = top;
- delete [] fSofties;
- }
- void
- RunView::FontChangeRecalc (void)
- {
- float width (Bounds().Width() - MARGIN_WIDTH);
- float top (0.0);
- for (int16 i = 0; i < fLine_count; ++i)
- {
- fLines[i]->fTop = top;
- fLines[i]->FigureSpaces();
- fLines[i]->FigureEdges (fTheme, width);
- top = fLines[i]->fBottom + 1.0;
- }
- if (fWorking)
- fWorking->fTop = top;
- RecalcScrollBar (false);
- if (!IsHidden())
- Invalidate (Bounds());
- if (Window()) Window()->UpdateIfNeeded();
- }
- bool
- RunView::RecalcScrollBar (bool constrain)
- {
- BScrollBar *bar;
- if (fScroller == NULL
- || (bar = fScroller->ScrollBar (B_VERTICAL)) == NULL)
- return false;
- float value (bar->Value());
- BRect bounds (Bounds());
- bool changed (false);
- float bottom (0.0);
- float scrollMin, scrollMax;
- bar->GetRange (&scrollMin, &scrollMax);
- if (fLine_count
- && (bounds.Contains (BPoint (0.0, 0.0)) == false
- || bounds.Contains (BPoint (0.0, fLines[fLine_count - 1]->fBottom)) == false))
- {
- bottom = fLines[fLine_count - 1]->fBottom + 5.0;
- bar->SetProportion (bounds.Height() / bottom);
- bar->SetSteps (10.0, bounds.Height());
- bottom -= bounds.Height();
- }
- // We don't want the bar to cause a draw/copybits, so we restrict the
- // clipping region to nothing
- if (constrain)
- {
- BRegion region;
- ConstrainClippingRegion (®ion);
- }
- if (scrollMax != bottom)
- {
- bar->SetRange (0.0, bottom);
- if (value == scrollMax || scrollMin == scrollMax)
- {
- bar->SetValue (bottom);
- changed = true;
- }
- }
- if (constrain)
- ConstrainClippingRegion (NULL);
- return changed;
- }
- void
- RunView::Append (
- const char *buffer,
- int16 fore,
- int16 back,
- int16 font)
- {
- Append (buffer, strlen (buffer), fore, back, font);
- }
- void
- RunView::Append (
- const char *buffer,
- int32 len,
- int16 fore,
- int16 back,
- int16 font)
- {
- if (buffer == NULL)
- return;
- float width (Bounds().Width() - 10);
- int32 place (0);
- assert (fore != Theme::TimestampFore);
- assert (back != Theme::TimestampBack);
- assert (font != Theme::TimestampFont);
- assert (fore != Theme::TimespaceFore);
- assert (back != Theme::TimespaceBack);
- assert (font != Theme::TimespaceFont);
- assert (back != Theme::SelectionBack);
- fTheme->ReadLock();
-
- while (place < len)
- {
- int32 end (place);
- while (end < len && buffer[end] != '\n')
- ++end;
- if (end < len) ++end;
- if (fWorking)
- {
- URLCrunch crunch (buffer + place, end - place);
- BString temp;
- int32 url_offset (0),
- last_offset (0);
- while ((url_offset = crunch.Crunch (&temp)) != B_ERROR)
- {
- fWorking->Append (buffer + place,
- (url_offset - last_offset),
- width,
- fTheme,
- fore,
- back,
- font);
- fWorking->Append (temp.String(),
- temp.Length(),
- width,
- fTheme,
- C_URL,
- back,
- F_URL);
- place += (url_offset - last_offset) + temp.Length();
- last_offset = url_offset + temp.Length();
- }
- if (place < end)
- fWorking->Append (
- buffer + place,
- end - place,
- width,
- fTheme,
- fore,
- back,
- font);
- }
- else
- {
- float top (0.0);
- if (fLine_count > 0)
- top = fLines[fLine_count - 1]->fBottom + 1.0;
- fWorking = new Line (
- buffer + place,
- 0,
- top,
- width,
- fTheme,
- fStamp_format,
- fore,
- back,
- font);
- URLCrunch crunch (buffer + place, end - place);
- BString temp;
- int32 url_offset (0),
- last_offset (0);
- while ((url_offset = crunch.Crunch (&temp)) != B_ERROR)
- {
- fWorking->Append (buffer + place,
- (url_offset - last_offset),
- width,
- fTheme,
- fore,
- back,
- font);
- fWorking->Append (temp.String(),
- temp.Length(),
- width,
- fTheme,
- C_URL,
- back,
- F_URL);
- place += (url_offset - last_offset) + temp.Length();
- last_offset = url_offset + temp.Length();
- }
- if (place < end)
- fWorking->Append (buffer + place,
- end - place,
- width,
- fTheme,
- fore,
- back,
- font);
- }
- if (fWorking->fLength
- && fWorking->fText[fWorking->fLength - 1] == '\n')
- {
- bool chopped;
- if (Window()) Window()->DisableUpdates();
- if ((chopped = (fLine_count == LINE_COUNT)))
- {
- Line *first (fLines[0]);
- float shift (first->fBottom + 1);
- for (int16 i = 1; i < LINE_COUNT; ++i)
- {
- fLines[i]->fTop -= shift;
- fLines[i]->fBottom -= shift;
- fLines[i - 1] = fLines[i];
- }
- fWorking->fTop -= shift;
- fWorking->fBottom -= shift;
- delete first;
-
- if (fSp_start.fLine > 0)
- fSp_start.fLine--;
- else
- fSp_start.fOffset = 0;
-
- if (fSp_end.fLine > 0)
- fSp_end.fLine--;
- else
- fSp_end.fOffset = 0;
- // Recalc the scrollbar so that we have clean drawing
- // after the line has been removed
- --fLine_count;
- RecalcScrollBar (true);
- }
- fLines[fLine_count++] = fWorking;
- RecalcScrollBar (true);
- Invalidate (Bounds());
- if (Window())
- {
- Window()->EnableUpdates();
- Window()->UpdateIfNeeded();
- }
- fWorking = NULL;
- }
- place = end;
- }
- fTheme->ReadUnlock();
- }
- void
- RunView::Clear (void)
- {
- for (int16 i = 0; i < fLine_count; ++i)
- delete fLines[i];
- fLine_count = 0;
- RecalcScrollBar (true);
- Invalidate();
- fSp_start.fLine = 0;
- fSp_start.fOffset = 0;
- fSp_end = fSp_start;
- if (fWorking)
- fWorking->fTop = 0.0;
- }
- int16
- RunView::LineCount (void) const
- {
- return fLine_count;
- }
- const char *
- RunView::LineAt (int16 which) const
- {
- if (which < 0 || which >= fLine_count)
- return NULL;
- return fLines[which]->fText;
- }
- void
- RunView::SetTimeStampFormat (const char *format)
- {
- if ((format == NULL
- && fStamp_format == NULL)
- || (format != NULL
- && fStamp_format != NULL
- && strcmp (format, fStamp_format) == 0))
- return;
- bool was_on (false);
- if (fStamp_format)
- {
- delete [] fStamp_format;
- fStamp_format = NULL;
- was_on = true;
- }
- if (format)
- fStamp_format = strcpy (new char [strlen (format) + 1], format);
- float width (Bounds().Width() - MARGIN_WIDTH);
- float top (0.0);
- fTheme->ReadLock();
- for (int16 i = 0; i < fLine_count; ++i)
- {
- fLines[i]->fTop = top;
- fLines[i]->SetStamp (fStamp_format, was_on);
- fLines[i]->FigureSpaces();
- fLines[i]->FigureEdges(fTheme, width);
- top = fLines[i]->fBottom + 1.0;
- }
- fTheme->ReadUnlock();
- if (fWorking)
- {
- fWorking->fTop = top;
- fWorking->SetStamp (fStamp_format, was_on);
- }
- RecalcScrollBar (false);
- Invalidate (Bounds());
- if (Window()) Window()->UpdateIfNeeded();
- }
- void
- RunView::SetTheme (Theme *t)
- {
- if (t == NULL || fTheme == t)
- return;
- fTheme = t;
- if (IsHidden())
- {
- fFontsdirty = true;
- return;
- }
- FontChangeRecalc();
- }
- SelectPos
- RunView::PositionAt (BPoint point) const
- {
- int16 i, lfIndex (0);
- SelectPos pos (-1, 0);
- if (fLine_count == 0)
- return pos;
- // find the line
- for (i = 0; i < fLine_count; ++i)
- {
- if (fLines[i]->fTop > point.y)
- break;
- lfIndex = i;
- }
- // check to make sure we actually did find a line and not just run into fLine_count
- if (fLines[lfIndex]->fBottom < point.y)
- {
- pos.fLine = fLine_count - 1;
- pos.fOffset = fLines[fLine_count - 1]->fLength;
- return pos;
- }
- float height (fLines[lfIndex]->fTop);
- int16 sfIndex (0);
- for (i = 0; i < fLines[lfIndex]->fSoftie_used; ++i)
- {
- if (height > point.y)
- break;
- sfIndex = i;
- height += fLines[lfIndex]->fSofties[i].fHeight;
- }
- float margin (MARGIN_WIDTH / 2.0);
- float width (0);
- int16 start (0);
- if (sfIndex)
- {
- int16 offset (fLines[lfIndex]->fSofties[sfIndex - 1].fOffset);
- width = fLines[lfIndex]->fEdges[offset];
- start = offset + UTF8_CHAR_LEN (fLines[lfIndex]->fText[offset]);
- }
- for (i = start; i <= fLines[lfIndex]->fSofties[sfIndex].fOffset; ++i)
- if (fLines[lfIndex]->fEdges[i] + margin - width >= point.x)
- break;
- pos.fLine = lfIndex;
- pos.fOffset = min_c (i, fLines[lfIndex]->fSofties[sfIndex].fOffset);
- if (pos.fOffset > 0) pos.fOffset += UTF8_CHAR_LEN (fLines[pos.fLine]->fText[pos.fOffset]);
- return pos;
- }
- BPoint
- RunView::PointAt (SelectPos s) const
- {
- return BPoint(fLines[s.fLine]->fTop + fLines[s.fLine]->fBottom / 2.0, fLines[s.fLine]->fEdges[s.fOffset]);
- }
- void
- RunView::GetSelectionText (BString &string) const
- {
- if (fSp_start == fSp_end)
- return;
- if (fSp_start.fLine == fSp_end.fLine)
- {
- const char *line (LineAt (fSp_start.fLine));
- string.Append (line + fSp_start.fOffset, fSp_end.fOffset - fSp_start.fOffset);
- return;
- }
- for (int32 i = fSp_start.fLine; i <= fSp_end.fLine; i++)
- {
- const char *line (LineAt (i));
- if (i == fSp_start.fLine)
- {
- line += fSp_start.fOffset;
- string.Append (line);
- }
- else if (i == fSp_end.fLine)
- {
- string.Append (line, fSp_end.fOffset);
- break;
- }
- else
- string.Append (line);
- }
- }
- bool
- RunView::IntersectSelection (const SelectPos &start, const SelectPos &end) const
- {
- if (fSp_start.fLine == fSp_end.fLine)
- {
- if (start.fLine == fSp_start.fLine && start.fOffset >= fSp_start.fOffset && start.fOffset < fSp_end.fOffset)
- return true;
- if (end.fLine == fSp_start.fLine && end.fOffset >= fSp_start.fOffset && end.fOffset < fSp_end.fOffset)
- return true;
- }
- else
- {
- if (start.fLine > fSp_start.fLine && start.fLine < fSp_end.fLine)
- return true;
- if (end.fLine > fSp_start.fLine && end.fLine < fSp_end.fLine)
- return true;
- if (start.fLine == fSp_start.fLine && start.fOffset >= fSp_start.fOffset)
- return true;
- if (end.fLine == fSp_start.fLine && end.fOffset >= fSp_start.fOffset)
- return true;
- if (start.fLine == fSp_end.fLine && start.fOffset < fSp_end.fOffset)
- return true;
- if (end.fLine == fSp_end.fLine && end.fOffset < fSp_end.fOffset)
- return true;
- }
- return false;
- }
- BRect
- RunView::GetTextFrame(const SelectPos &start, const SelectPos &end) const
- {
- return BRect (0.0, fLines[(start.fLine > 0) ? (start.fLine - 1) : 0]->fTop,
- Bounds().Width(), fLines[end.fLine]->fBottom);
- }
- void
- RunView::Select (const SelectPos &start, const SelectPos &end)
- {
- if (fSp_start != fSp_end)
- {
- if (start == end || !IntersectSelection (start, end))
- {
- BRect frame (GetTextFrame (fSp_start, fSp_end));
- fSp_start = start;
- fSp_end = start;
- Invalidate (frame);
- }
- else
- {
- if (fSp_start.fLine < start.fLine || (fSp_start.fLine == start.fLine && fSp_start.fOffset < start.fOffset))
- {
- BRect frame (GetTextFrame (fSp_start, start));
- fSp_start = start;
- Invalidate (frame);
- }
- if (end.fLine < fSp_end.fLine || (fSp_end.fLine == end.fLine && end.fOffset < fSp_end.fOffset))
- {
- BRect frame (GetTextFrame (end, fSp_end));
- fSp_end = end;
- Invalidate (frame);
- }
- }
- }
- if (fSp_start == fSp_end)
- {
- fSp_start = start;
- fSp_end = end;
- if (fSp_start != fSp_end)
- {
- BRect frame (GetTextFrame (start, end));
- Invalidate (frame);
- }
- }
- else // extension
- {
- if (start.fLine < fSp_start.fLine || (start.fLine == fSp_start.fLine && start.fOffset < fSp_start.fOffset))
- {
- BRect frame (GetTextFrame (start, fSp_start));
- fSp_start = start;
- Invalidate (frame);
- }
- if (end.fLine > fSp_end.fLine || (end.fLine == fSp_end.fLine && end.fOffset > fSp_end.fOffset))
- {
- BRect frame (GetTextFrame (fSp_end, end));
- fSp_end = end;
- Invalidate (frame);
- }
- }
- }
- void
- RunView::SelectAll (void)
- {
- if (fLine_count)
- {
- fSp_start = SelectPos (0, 0);
- fSp_end = SelectPos (fLine_count-1, fLines[fLine_count-1]->fLength);
- Invalidate(Bounds());
- }
- }
- void
- RunView::SetClippingName (const char *name)
- {
- delete [] fClipping_name;
- fClipping_name = new char[strlen(name) + 1];
- memcpy (fClipping_name, name, strlen(name));
- fClipping_name[strlen(name)] = '\0';
- }
- Line::Line (
- const char *buffer,
- int16 len,
- float top,
- float width,
- Theme *theme,
- const char *stamp_format,
- int16 fore,
- int16 back,
- int16 font)
- : fText (NULL),
- fStamp (time(NULL)),
- fUrls (NULL),
- fSpaces (NULL),
- fEdges (NULL),
- fFcs (NULL),
- fSofties (NULL),
- fTop (top),
- fBottom (0.0),
- fLength (len),
- fSpace_count (0),
- fEdge_count (0),
- fFc_count (0),
- fSoftie_size (0),
- fSoftie_used (0)
- {
- // Very important to call SetStamp before Append, It would look real funny otherwise!
- SetStamp( stamp_format, false );
- Append( buffer, len, width, theme, fore, back, font );
- }
- Line::~Line (void)
- {
- delete [] fSpaces;
- delete [] fEdges;
- delete [] fFcs;
- delete [] fText;
- delete [] fSofties;
-
- if (fUrls)
- {
- while (fUrls->CountItems() > 0)
- delete fUrls->RemoveItemAt(0L);
- delete fUrls;
- }
- }
- void
- Line::Append (
- const char *buffer,
- int16 len,
- float width,
- Theme *theme,
- int16 fore,
- int16 back,
- int16 font)
- {
- int16 save (fLength);
- char *new_fText;
- new_fText = new char [fLength + len + 1];
- if (fText != NULL)
- {
- memcpy (new_fText, fText, fLength);
- delete [] fText;
- }
- memcpy (new_fText + fLength, buffer, len);
- fLength += len;
- new_fText[fLength] = '\0';
- // replace Tab chars with spaces.
- // todo: This should be temp until RunView can properly
- // display tabs.
- for( char* pos = new_fText + save; *pos; ++pos )
- {
- if( '\t' == *pos )
- {
- *pos = ' ';
- }
- }
-
- fText = new_fText;
- FigureFontColors (save, fore, back, font);
- if (fore == C_URL)
- {
- if (!fUrls)
- fUrls = new urllist;
- fUrls->AddItem (new URL (buffer, save, len));
- }
- if (fText[fLength - 1] == '\n')
- {
- FigureSpaces();
- FigureEdges (theme, width);
- }
- }
- void
- Line::FigureSpaces (void)
- {
- const char spacers[] = " \t\n-\\/";
- const char *buffer (fText);
- size_t offset (0), n;
- int16 count (0);
- delete [] fSpaces;
- fSpace_count = 0;
- while ((n = strcspn (buffer + offset, spacers)) < fLength - offset)
- {
- ++count;
- offset += n + 1;
- }
- fSpaces = new int16 [count];
- offset = 0;
- while ((n = strcspn (buffer + offset, spacers)) < fLength - offset)
- {
- fSpaces[fSpace_count++] = n + offset;
- offset += n + 1;
- }
- }
- void
- Line::FigureFontColors (
- int16 pos,
- int16 fore,
- int16 back,
- int16 font)
- {
- if (fFc_count)
- {
- int16 last_fore = -1;
- int16 last_back = -1;
- int16 last_font = -1;
- int16 i;
- // we have fFcs, so we backtrack for last of each fWhich
- for (i = fFc_count - 1; i >= 0; --i)
- {
- if (last_fore < 0
- && fFcs[i].fWhich == FORE_WHICH)
- last_fore = i;
- else if (last_back < 0
- && fFcs[i].fWhich == BACK_WHICH)
- last_back = i;
- else if (last_font < 0
- && fFcs[i].fWhich == FONT_WHICH)
- last_font = i;
- if (last_fore >= 0
- && last_back >= 0
- && last_font >= 0)
- break;
- }
- // now figure out how many more we need
- int16 count = 0;
- if (fFcs[last_fore].fIndex != fore)
- ++count;
- if (fFcs[last_back].fIndex != back)
- ++count;
- if (fFcs[last_font].fIndex != font)
- ++count;
- if (count)
- {
- FontColor *new_fFcs;
- new_fFcs = new FontColor [fFc_count + count];
- memcpy (new_fFcs, fFcs, fFc_count * sizeof (FontColor));
- delete [] fFcs;
- fFcs = new_fFcs;
- if (fFcs[last_fore].fIndex != fore)
- {
- fFcs[fFc_count].fWhich = FORE_WHICH;
- fFcs[fFc_count].fOffset = pos;
- fFcs[fFc_count].fIndex = fore;
- ++fFc_count;
- }
- if (fFcs[last_back].fIndex != back)
- {
- fFcs[fFc_count].fWhich = BACK_WHICH;
- fFcs[fFc_count].fOffset = pos;
- fFcs[fFc_count].fIndex = back;
- ++fFc_count;
- }
- if (fFcs[last_font].fIndex != font)
- {
- fFcs[fFc_count].fWhich = FONT_WHICH;
- fFcs[fFc_count].fOffset = pos;
- fFcs[fFc_count].fIndex = font;
- ++fFc_count;
- }
- }
- }
- else
- {
- fFcs = new FontColor [fFc_count = 3];
- fFcs[0].fWhich = FORE_WHICH;
- fFcs[0].fOffset = 0;
- fFcs[0].fIndex = fore;
- fFcs[1].fWhich = BACK_WHICH;
- fFcs[1].fOffset = 0;
- fFcs[1].fIndex = back;
- fFcs[2].fWhich = FONT_WHICH;
- fFcs[2].fOffset = 0;
- fFcs[2].fIndex = font;
- }
- }
- void
- Line::FigureEdges (
- Theme *theme,
- float width)
- {
- delete [] fEdges;
- fEdges = new int16 [fLength];
- int16 cur_fFcs (0), next_fFcs (0), cur_font (0);
- fEdge_count = 0;
- while (cur_fFcs < fFc_count)
- {
- if (fFcs[cur_fFcs].fWhich == FONT_WHICH)
- {
- cur_font = cur_fFcs;
- break;
- }
- ++cur_fFcs;
- }
- while (cur_fFcs < fFc_count)
- {
- int16 last_offset (fFcs[cur_fFcs].fOffset);
- next_fFcs = cur_fFcs + 1;
- while (next_fFcs < fFc_count)
- {
- // We want to break at every difference
- // but, we want to break on a font if available
- if (fFcs[next_fFcs].fOffset > last_offset)
- {
- while (next_fFcs < fFc_count
- && fFcs[next_fFcs].fWhich != FONT_WHICH
- && next_fFcs + 1 < fFc_count
- && fFcs[next_fFcs + 1].fOffset == fFcs[next_fFcs].fOffset)
- ++next_fFcs;
- break;
- }
- ++next_fFcs;
- }
- if (fFcs[cur_fFcs].fWhich == FONT_WHICH)
- cur_font = cur_fFcs;
- int16 ccount;
- int16 seglen;
- if (next_fFcs == fFc_count)
- {
- ccount = CountChars (fFcs[cur_fFcs].fOffset, fLength - fFcs[cur_fFcs].fOffset);
- seglen = fLength - fFcs[cur_fFcs].fOffset;
- }
- else
- {
- ccount = CountChars (
- fFcs[cur_fFcs].fOffset,
- fFcs[next_fFcs].fOffset - fFcs[cur_fFcs].fOffset);
- seglen = fFcs[next_fFcs].fOffset - fFcs[cur_fFcs].fOffset;
- }
- const BFont &f (theme->FontAt (fFcs[cur_font].fIndex));
- #ifdef __INTEL__
- float eshift[ccount];
- #else
- float *eshift = new float[ccount];
- #endif
- f.GetEscapements (
- fText + fFcs[cur_fFcs].fOffset,
- ccount,
- eshift);
- // This is not perfect, because we are including the left edge,
- // but BFont::GetEdges doesn't seem to work as we'd like
- int16 i;
-
- float incrementor = (fEdge_count > 0) ? fEdges[fEdge_count - 1] : 0;
-
- for (i = 0; i < ccount; ++i)
- {
- incrementor += eshift[i] * f.Size();
- fEdges[fEdge_count+i] = (int16) incrementor;
-
- // this little backfTracking routine is necessary in the case where an fFcs change
- // comes immediately after a UTF8-char, since all but the first edge will be 0
- // and thus the new edge's starting position will be thrown off if we don't
- // backtrack to the beginning of the char
- if ((fEdge_count + i > 0) && fEdges[fEdge_count + i - 1] == 0)
- {
- int32 temp = fEdge_count + i - 1;
- while (fEdges[--temp] == 0);
- fEdges[fEdge_count + i] += fEdges[temp];
- }
- }
- for (i = fFcs[cur_fFcs].fOffset; i < fFcs[cur_fFcs].fOffset + seglen;)
- {
- int32 len (UTF8_CHAR_LEN (fText[i]) - 1);
- if (len)
- {
- int16 k;
- for (k = fEdge_count + ccount - 1; k > i; --k)
- fEdges[k + len] = fEdges[k];
- for (k = 1; k <= len; ++k)
- fEdges[i + k] = 0;
- ccount += len;
- }
- i += len + 1;
- }
- cur_fFcs = next_fFcs;
- fEdge_count += ccount;
- #ifndef __INTEL__
- delete [] eshift;
- #endif
- }
- SoftBreaks (theme, width);
- }
- void
- Line::AddSoftBreak (SoftBreakEnd sbe, float &start, uint16 &fText_place,
- int16 &font, float &width, float &start_width, Theme *theme)
- {
- fText_place = sbe.fOffset;
- if (fSoftie_size < fSoftie_used + 1)
- {
- SoftBreak *new_softies;
- new_softies = new SoftBreak [fSoftie_size += SOFTBREAK_STEP];
- if (fSofties)
- {
- memcpy (new_softies, fSofties, sizeof (SoftBreak) * fSoftie_used);
- delete [] fSofties;
- }
- fSofties = new_softies;
- }
- // consume whitespace
- while (fText_place + 1 < fLength
- && isspace (fText[fText_place + 1]))
- ++fText_place;
- fSofties[fSoftie_used].fOffset = fText_place;
- fSofties[fSoftie_used].fHeight = 0.0;
- fSofties[fSoftie_used].fAscent = 0.0;
- int16 last (font);
- while (font < fFc_count)
- {
- const BFont &f (theme->FontAt (fFcs[font].fIndex));
- font_height fh;
- float height;
- f.GetHeight (&fh);
- height = ceil (fh.ascent + fh.descent + fh.leading);
- if (fSofties[fSoftie_used].fHeight < height)
- fSofties[fSoftie_used].fHeight = height;
- if (fSofties[fSoftie_used].fAscent < fh.ascent)
- fSofties[fSoftie_used].fAscent = fh.ascent;
- // now try and find next
- while (++font < fFc_count)
- if (fFcs[font].fWhich == FONT_WHICH)
- break;
- if (font == fFc_count
- || fFcs[font].fOffset > fText_place)
- {
- font = last;
- break;
- }
- last = font;
- }
- if (fText_place < fLength)
- start = fEdges[fText_place];
- fBottom += fSofties[fSoftie_used++].fHeight;
- fText_place += UTF8_CHAR_LEN (fText[fText_place]);
- width = start_width - MARGIN_INDENT;
- }
- void
- Line::SoftBreaks (Theme *theme, float start_width)
- {
- float margin (ceil (MARGIN_WIDTH / 2.0));
- float width (start_width);
- float start (0.0);
- uint16 fText_place (0);
- int16 space_place (0);
- int16 font (0);
- fSoftie_used = 0;
- fBottom = fTop;
- // find first font
- while (font < fFc_count && fFcs[font].fWhich != FONT_WHICH)
- ++font;
- while (fText_place < fLength)
- {
- while (space_place < fSpace_count)
- {
- if (fEdges[fSpaces[space_place]] - start > width)
- break;
- ++space_place;
- }
- // we've reached the end of the line (but it might not all fit)
- // or we only have one space, so we check if we need to split the word
- if (space_place == fSpace_count
- || space_place == 0
- || fSpaces[space_place - 1] < fText_place)
- {
- // everything fits.. how wonderful (but we want at least one softbreak)
- if (fEdge_count == 0)
- {
- AddSoftBreak (SoftBreakEnd(fLength - 1), start, fText_place, font, width, start_width, theme);
- break;
- }
- int16 i (fEdge_count - 1);
- while (fEdges[i] == 0)
- --i;
-
- if (fEdges[i] - start <= width)
- {
- AddSoftBreak (SoftBreakEnd(fLength - 1), start, fText_place, font, width, start_width, theme);
- continue;
- }
- // we force at least one character
- // your font may be a little too large for your window!
- fText_place += UTF8_CHAR_LEN (fText[fText_place]);
- while (fText_place < fLength)
- {
- if (fEdges[fText_place] - start > width - margin)
- break;
- fText_place += UTF8_CHAR_LEN (fText[fText_place]);
- }
- AddSoftBreak (SoftBreakEnd(fText_place), start, fText_place, font, width, start_width, theme);
- continue;
- }
- // we encountered more than one space, so we rule out having to
- // split the word, if the current word will fit within the bounds
- int16 ccount1, ccount2;
- --space_place;
- ccount1 = fSpaces[space_place];
- ccount2 = fSpaces[space_place+1] - ccount1;
- int16 i (ccount1 - 1);
- while (fEdges[i] == 0)
- --i;
-
- if (fEdges[ccount1 + ccount2] - fEdges[i] < width - margin)
- {
- AddSoftBreak (SoftBreakEnd(fSpaces[space_place]), start, fText_place, font, width, start_width, theme);
- continue;
- }
- // We need to break up the really long word
- fText_place = fSpaces[space_place];
- while (fText_place < fEdge_count)
- {
- if ((fEdges[fText_place] - start) > width)
- break;
- fText_place += UTF8_CHAR_LEN (fText[fText_place]);
- }
- }
- fBottom -= 1.0;
- }
- int16
- Line::CountChars (int16 pos, int16 len)
- {
- int16 ccount (0);
- if (pos >= fLength)
- return ccount;
- if (pos + len > fLength)
- len = fLength - pos;
- register int16 i = pos;
- while (i < pos + len)
- {
- i += UTF8_CHAR_LEN(fText[i]);
- ++ccount;
- }
- return ccount;
- }
- size_t
- Line::SetStamp (const char *format, bool was_on)
- {
- size_t size (0);
- int32 i (0);
-
- if (was_on)
- {
- int16 offset (fFcs[4].fOffset + 1);
- if (fUrls)
- {
- for (i = 0; i < fUrls->CountItems(); i++)
- fUrls->ItemAt(i)->fOffset -= offset;
- }
- memmove (fText, fText + offset, fLength - offset);
- fText[fLength -= offset] = '\0';
- for (i = 6; i < fFc_count; ++i)
- {
- fFcs[i].fOffset -= offset;
- fFcs[i - 6] = fFcs[i];
- }
- fFc_count -= 6;
- }
- if (format)
- {
- char buffer[1024];
- struct tm curTime;
- localtime_r (&fStamp, &curTime);
- size = strftime (buffer, 1023, format, &curTime);
- if (fUrls)
- {
- for (i = 0; i < fUrls->CountItems(); i++)
- fUrls->ItemAt(i)->fOffset += size;
- }
- char *new_fText;
- new_fText = new char [fLength + size + 2];
- memcpy (new_fText, buffer, size);
- new_fText[size++] = ' ';
- new_fText[size] = '\0';
- if (fText)
- {
- memcpy (new_fText + size, fText, fLength);
- delete [] fText;
- }
- fText = new_fText;
- fText[fLength += size] = '\0';
- FontColor *new_fFcs;
- new_fFcs = new FontColor [fFc_count + 6];
- if (fFcs)
- {
- memcpy (
- new_fFcs + 6,
- fFcs,
- fFc_count * sizeof (FontColor));
- delete [] fFcs;
- }
- fFcs = new_fFcs;
- fFc_count += 6;
- fFcs[0].fWhich = FORE_WHICH;
- fFcs[0].fIndex = Theme::TimestampFore;
- fFcs[0].fOffset = 0;
- fFcs[1].fWhich = BACK_WHICH;
- fFcs[1].fIndex = Theme::TimestampBack;
- fFcs[1].fOffset = 0;
- fFcs[2].fWhich = FONT_WHICH;
- fFcs[2].fIndex = Theme::TimestampFont;
- fFcs[2].fOffset = 0;
- fFcs[3].fWhich = FORE_WHICH;
- fFcs[3].fIndex = Theme::TimespaceFore;
- fFcs[3].fOffset = size - 1;
- fFcs[4].fWhich = BACK_WHICH;
- fFcs[4].fIndex = Theme::TimespaceBack;
- fFcs[4].fOffset = size - 1;
- fFcs[5].fWhich = FONT_WHICH;
- fFcs[5].fIndex = Theme::TimespaceFont;
- fFcs[5].fOffset = size - 1;
- for (i = 6; i < fFc_count; ++i)
- fFcs[i].fOffset += size;
- }
- return size;
- }
- void
- Line::SelectWord (int16 *start, int16 *end)
- {
- int16 start_tmp (*start), end_tmp (*end);
- while(start_tmp > 0 && fText[start_tmp-1] != ' ')
- start_tmp--;
- while ((end_tmp - 1) < fLength && fText[end_tmp] != ' ')
- end_tmp++;
- while (end_tmp >= fLength)
- --end_tmp;
- *start = start_tmp;
- *end = end_tmp;
- }
- bool
- RunView::FindText(const char *text)
- {
- bool result (false);
- if (text != NULL)
- {
- for (int32 i = 0; i < fLine_count; i++)
- {
- char *offset (NULL);
- if ((offset = strstr(fLines[i]->fText, text)) != NULL)
- {
- SelectPos start (i, offset - text),
- end (i, (offset - text) + strlen(text));
- Select(start, end);
- ScrollTo(0.0, fLines[i]->fTop);
- result = true;
- break;
- }
- }
- }
- return result;
- }
- void
- RunView::ScrollToSelection(void)
- {
- if (fLine_count > 0)
- {
- if (fSp_start != fSp_end)
- {
- ScrollTo(0.0, fLines[fSp_start.fLine]->fTop);
- }
- }
- }
- void
- RunView::ScrollToBottom(void)
- {
- if (fLine_count > 0)
- {
- ScrollTo(0.0, fLines[fLine_count - 1]->fTop);
- }
- }
|