OSDN Git Service

lvwLog is now owner-drawn
[winbottle/winbottle.git] / bottleclient / LogForm.pas
1 unit LogForm;
2
3 interface
4
5 uses
6   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
7   ComCtrls, ToolWin, StdCtrls, ExtCtrls, SsParser, BottleDef, Menus,
8   Clipbrd, Logs, ShellAPI, Commctrl, DirectSstp, Contnrs, StrUtils;
9
10 type
11   TSaveLogType = (stLog, stLogWithChannels, stText, stXML);
12
13   TfrmLog = class(TForm)
14     ToolBar: TToolBar;
15     tbtnClear: TToolButton;
16     pnlUpper: TPanel;
17     SsParser: TSsParser;
18     StatusBar: TStatusBar;
19     tbtnSaveLog: TToolButton;
20     PopupMenuPreview: TPopupMenu;
21     mnPopCopy: TMenuItem;
22     tbtnVoteMessage: TToolButton;
23     PopupMenuListView: TPopupMenu;
24     mnPopUpVoteMessage: TMenuItem;
25     SaveDialog: TSaveDialog;
26     pnlPanel: TPanel;
27     Splitter: TSplitter;
28     edtScript: TRichEdit;
29     mnPopUpCopyScript: TMenuItem;
30     PopupMenuSaveLog: TPopupMenu;
31     mnSaveLog: TMenuItem;
32     mnSaveLogChannel: TMenuItem;
33     mnSaveLogScript: TMenuItem;
34     mnSaveLogXML: TMenuItem;
35     ToolButton1: TToolButton;
36     mnJumpURL: TMenuItem;
37     mnPopUpAgreeMessage: TMenuItem;
38     tbtnAgreeMessage: TToolButton;
39     ToolButton2: TToolButton;
40     tbtnPreviewStyle: TToolButton;
41     PopupMenuPreviewStyle: TPopupMenu;
42     mnPreviewStyleConversation: TMenuItem;
43     mnPreviewStyleScript: TMenuItem;
44     mnPreviewStyleScriptWithLineBreak: TMenuItem;
45     Panel1: TPanel;
46     tabBottleLog: TTabControl;
47     lvwLog: TListView;
48     tbtnDownloadLog: TToolButton;
49     PopupMenuTab: TPopupMenu;
50     mnCloseTab: TMenuItem;
51     tbtnFindBottle: TToolButton;
52     tbtnOpenLog: TToolButton;
53     OpenDialog: TOpenDialog;
54     tbtnInsertCue: TToolButton;
55     mnInsertCue: TMenuItem;
56     PopupMenuListPreviewStyle: TPopupMenu;
57     mnListPreviewStyleNormal: TMenuItem;
58     mnListPreviewStyleTagStripped: TMenuItem;
59     tbtnListPreviewStyle: TToolButton;
60     procedure tbtnClearClick(Sender: TObject);
61     procedure FormCreate(Sender: TObject);
62     procedure lvwLogChange(Sender: TObject; Item: TListItem;
63       Change: TItemChange);
64     procedure lvwLogDblClick(Sender: TObject);
65     procedure lvwLogKeyPress(Sender: TObject; var Key: Char);
66     procedure FormDestroy(Sender: TObject);
67     procedure lvwLogClick(Sender: TObject);
68     procedure mnSaveLogClick(Sender: TObject);
69     procedure lvwLogColumnClick(Sender: TObject; Column: TListColumn);
70     procedure mnPopUpCopyScriptClick(Sender: TObject);
71     procedure mnSaveLogChannelClick(Sender: TObject);
72     procedure mnSaveLogScriptClick(Sender: TObject);
73     procedure mnSaveLogXMLClick(Sender: TObject);
74     procedure lvwLogData(Sender: TObject; Item: TListItem);
75     procedure PopupMenuListViewPopup(Sender: TObject);
76     procedure lvwLogCustomDrawItem(Sender: TCustomListView;
77       Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
78     procedure PopupMenuPreviewStylePopup(Sender: TObject);
79     procedure mnPreviewStyleClick(Sender: TObject);
80     procedure tbtnPreviewStyleClick(Sender: TObject);
81     procedure tabBottleLogChange(Sender: TObject);
82     procedure tabBottleLogChanging(Sender: TObject;
83       var AllowChange: Boolean);
84     procedure tabBottleLogContextPopup(Sender: TObject; MousePos: TPoint;
85       var Handled: Boolean);
86     procedure mnCloseTabClick(Sender: TObject);
87     procedure tbtnFindBottleClick(Sender: TObject);
88     procedure tbtnOpenLogClick(Sender: TObject);
89     procedure tabBottleLogMouseDown(Sender: TObject; Button: TMouseButton;
90       Shift: TShiftState; X, Y: Integer);
91     procedure tabBottleLogDragOver(Sender, Source: TObject; X, Y: Integer;
92       State: TDragState; var Accept: Boolean);
93     procedure tabBottleLogDragDrop(Sender, Source: TObject; X, Y: Integer);
94     procedure tabBottleLogEndDrag(Sender, Target: TObject; X, Y: Integer);
95     procedure lvwLogDrawItem(Sender: TCustomListView; Item: TListItem;
96       Rect: TRect; State: TOwnerDrawState);
97     procedure mnListPreviewStyleTagStrippedClick(Sender: TObject);
98     procedure tbtnListPreviewStyleClick(Sender: TObject);
99     procedure PopupMenuListPreviewStylePopup(Sender: TObject);
100   private
101     { Private \90é\8c¾ }
102     FLastScript: String; //\83X\83N\83\8a\83v\83g\8dÄ\95`\89æ\97}\90§\97p
103     FBottleLogList: TObjectList;
104     //
105     FDragTabIndex: integer; //\83^\83u\83h\83\89\83b\83O\83h\83\8d\83b\83v\8aÖ\98A
106     FDragTabDest: integer;  //\83h\83\8d\83b\83v\82·\82é\88Ê\92u(\82·\82®\89E\82É\82­\82é\83^\83u\82Ì\83C\83\93\83f\83b\83N\83X)
107     //
108     procedure UpdateScript(const Script: String);
109     procedure UpdateScriptConversationColor(const Script: String);
110     procedure UpdateScriptScript(const Script: String);
111     procedure mnURLClick(Sender: TObject);
112     procedure ExtractURLs(Script: String; Result: TStrings);
113     function GetDefaultFileName(const Name: String; const Ext: String): String;
114     function BottleLogTitled(const LogName: String): TBottleLogList;
115     procedure DrawSingleLineScript(const Script: String; const Rect: TRect;
116       Item: TListItem);
117   protected
118     procedure CreateParams(var Params: TCreateParams); override;
119   public
120     { Public \90é\8c¾ }
121     function SelectedBottleLog: TBottleLogList;
122     property BottleLogList: TObjectList read FBottleLogList;
123     procedure AddCurrentScriptLog(const LogName, Script, Channel, MID, Ghost: String);
124     procedure AddCurrentSystemLog(const LogName, MessageString: String);
125     procedure VoteLog(const MID: String; const Vote: integer);
126     procedure AgreeLog(const MID: String; const Agree: integer);
127     procedure SetBottleState(const MID: String; State: TLogState);
128     procedure AllBottleOpened;
129     procedure LogLoaded(Sender: TObject);
130     procedure LogLoadFailure(Sender: TObject; const Message: String);
131     procedure LogLoadWork(Sender: TObject);
132     procedure UpdateTab;
133     procedure UpdateWindow;
134     procedure SelAndFocusMessage(const MID: String);
135   end;
136
137
138 var
139   frmLog: TfrmLog;
140
141 const
142   IconBottle    = 17;
143   IconOpened    = 30;
144   IconPlaying   = 31;
145   IconSystemLog = 26;
146   SubChannel    = 0;
147   SubGhost      = 1;
148   SubVotes      = 2;
149   SubAgrees     = 3;
150   SubScript     = 4;
151
152 implementation
153
154 uses MainForm;
155
156 {$R *.DFM}
157
158 { TfrmLog }
159
160 procedure TfrmLog.AddCurrentScriptLog(const LogName, Script, Channel, MID, Ghost: String);
161 var Sel: integer;
162 begin
163   BottleLogTitled(LogName).AddScriptLog(Script, Channel, MID, Ghost);
164   if SelectedBottleLog <> BottleLogTitled(LogName) then Exit;
165   lvwLog.OnChange := nil; //\83C\83x\83\93\83g\94­\90¶(\82¢\82ë\82¢\82ë\8dÄ\95`\89æ\82ª\8bN\82«\82é)\82Ì\97}\90§
166   if lvwLog.Selected <> nil then Sel := lvwLog.Selected.Index else Sel := -1;
167   lvwLog.Items.Count := SelectedBottleLog.Count;
168   UpdateWindow;
169   if Sel >= 0 then begin
170     lvwLog.Selected := lvwLog.Items[Sel + 1];
171     lvwLog.Selected.Focused := true;
172   end;
173   if not lvwLog.Focused then
174     ListView_Scroll(lvwLog.Handle, 0, High(integer));
175   lvwLog.OnChange := lvwLogChange;
176 end;
177
178 procedure TfrmLog.AddCurrentSystemLog(const LogName, MessageString: String);
179 var Sel: integer;
180 begin
181   BottleLogTitled(LogName).AddSystemLog(MessageString);
182   if SelectedBottleLog <> BottleLogTitled(LogName) then Exit;
183   lvwLog.OnChange := nil;
184   if lvwLog.Selected <> nil then Sel := lvwLog.Selected.Index else Sel := -1;
185   lvwLog.Items.Count := SelectedBottleLog.Count;
186   UpdateWindow;
187   if Sel >= 0 then begin
188     lvwLog.Selected := lvwLog.Items[Sel + 1];
189     lvwLog.Selected.Focused := true;
190   end;
191   if not lvwLog.Focused then
192     ListView_Scroll(lvwLog.Handle, 0, High(integer));
193   lvwLog.OnChange := lvwLogChange;
194 end;
195
196
197
198 procedure TfrmLog.tbtnClearClick(Sender: TObject);
199 begin
200   if SelectedBottleLog = nil then Exit;
201   FBottleLogList.Delete(tabBottleLog.TabIndex);
202   tabBottleLog.TabIndex := 0;
203   UpdateTab;
204   UpdateWindow;
205   lvwLogChange(Self, nil, ctState);
206 end;
207
208 procedure TfrmLog.FormCreate(Sender: TObject);
209 var i: integer;
210 begin
211   FBottleLogList := TObjectList.Create;
212
213   SsParser.TagPattern.Assign(frmSender.SsParser.TagPattern);
214   SsParser.MetaPattern.Assign(frmSender.SsParser.MetaPattern);
215
216   with Pref.LogWindowPosition do begin
217     Self.Left   := Left;
218     Self.Top    := Top;
219     Self.Width  := Right - Left + 1;
220     Self.Height := Bottom - Top + 1;
221   end;
222   lvwLog.DoubleBuffered := true;
223   edtScript.Height := Pref.LogWindowDividerPos;
224
225   i := 0;
226   while Token(Pref.LogWindowColumnWidth, ',', i) <> '' do begin
227     lvwLog.Columns[i].Width := StrToIntDef(Token(Pref.LogWindowColumnWidth, ',', i), 100);
228     Inc(i);
229   end;
230
231   UpdateWindow; // Reset window color and enabled status of some buttons
232 end;
233
234 procedure TfrmLog.FormDestroy(Sender: TObject);
235 var i: integer;
236     WidthStr: String;
237 begin
238   WidthStr := '';
239   for i := 0 to lvwLog.Columns.Count-1 do begin
240     if i > 0 then WidthStr := WidthStr + ',';
241     WidthStr := WidthStr + IntToStr(lvwLog.Column[i].Width);
242   end;
243   Pref.LogWindowColumnWidth := WidthStr;
244
245   with Pref.LogWindowPosition do begin
246     Left   := Self.Left;
247     Top    := Self.Top;
248     Right  := Self.Left + Self.Width - 1;
249     Bottom := Self.Top + Self.Height - 1;
250   end;
251   Pref.LogWindowDividerPos := edtScript.Height;
252
253   FreeAndNil(FBottleLogList);
254 end;
255
256 procedure TfrmLog.lvwLogChange(Sender: TObject; Item: TListItem;
257   Change: TItemChange);
258 var Script: String;
259     Log: TLogItem;
260 begin
261   if SelectedBottleLog <> nil then begin
262     StatusBar.Panels[0].Text := IntToStr(SelectedBottleLog.Count) + '\8c\8f';
263     if Change = ctState then begin
264       Script := '';
265       if lvwLog.Selected <> nil then begin
266         Log := SelectedBottleLog.Bottles[lvwLog.Selected.Index];
267         if (Log.LogType = ltBottle) and not frmSender.Connecting then begin
268           Script := Log.Script;
269           frmSender.actVoteMessage.Enabled := true;
270           frmSender.actAgreeMessage.Enabled := true;
271           frmSender.actInsertCue.Enabled := true;
272           mnPopUpCopyScript.Enabled := true;
273           StatusBar.Panels[1].Text := Format('%d\83o\83C\83g - \83_\83u\83\8b\83N\83\8a\83b\83N\82Å\8dÄ\90¶', [Length(Log.Script)]);
274           UpdateScript(Script);
275         end else begin
276           frmSender.actVoteMessage.Enabled := false;
277           frmSender.actAgreeMessage.Enabled := false;
278           frmSender.actInsertCue.Enabled := false;
279           mnPopUpCopyScript.Enabled := false;
280           StatusBar.Panels[1].Text := '';
281           UpdateScript(''); // \83\8d\83O\83v\83\8c\83r\83\85\81[\95\94\82ð\83N\83\8a\83A
282         end;
283       end else begin
284         frmSender.actVoteMessage.Enabled := false;
285         frmSender.actAgreeMessage.Enabled := false;
286         frmSender.actInsertCue.Enabled := false;
287         mnPopUpCopyScript.Enabled := false;
288         StatusBar.Panels[1].Text := '';
289         UpdateScript(Script); // \83\8d\83O\83v\83\8c\83r\83\85\81[\95\94\83N\83\8a\83A
290       end;
291     end;
292     tbtnSaveLog.Enabled := lvwLog.Items.Count > 0;
293   end else begin
294     frmSender.actVoteMessage.Enabled := false;
295     frmSender.actAgreeMessage.Enabled := false;
296     frmSender.actInsertCue.Enabled := false;
297     mnPopUpCopyScript.Enabled := false;
298     StatusBar.Panels[0].Text := '';
299     UpdateScript(''); // \83\8d\83O\83v\83\8c\83r\83\85\81[\95\94\83N\83\8a\83A
300   end;
301 end;
302
303 procedure TfrmLog.lvwLogDblClick(Sender: TObject);
304 var Script: String;
305     Log, CueItem: TLogItem;
306 begin
307   if lvwLog.Selected = nil then
308     Exit;
309   Log := SelectedBottleLog.Bottles[lvwLog.Selected.Index];
310   if Log = nil then Exit;
311   if Log.LogType <> ltBottle then
312     Exit;
313   Script := frmSender.ScriptTransForSSTP(Log.Script);
314   if Script = '' then begin
315     ShowMessage('\96â\91è\82Ì\82 \82é\83X\83N\83\8a\83v\83g\82Å\82·\81B\8dÄ\90\82Å\82«\82Ü\82¹\82ñ\81B'+
316       '\83N\83\89\83C\83A\83\93\83g\82ð\8dÅ\90V\94Å\82É\82µ\82Ä\82Ý\82Ä\82­\82¾\82³\82¢\81B');
317     Exit;
318   end;
319
320   CueItem := TLogItem.Create(Log);
321   try
322     CueItem.Script := Script;
323     frmSender.BottleSstp.Unshift(CueItem);
324   except
325     CueItem.Free;
326   end;
327 end;
328
329 procedure TfrmLog.UpdateScriptConversationColor(const Script: String);
330 var i: integer;
331     scr: String;
332     UnyuTalking, Talked, InSynchronized: boolean;
333 begin
334   scr := Script;
335   frmSender.DoTrans(scr, [toConvertURL]);
336   SsParser.LeaveEscape := false;
337   SsParser.InputString := scr;
338   SsParser.LeaveEscape := true;
339   UnyuTalking := false;
340   Talked := false; //'\h\u\h\u'\82Ì\82æ\82¤\82È\83X\83N\83\8a\83v\83g\82Å\8bó\82«\8ds\82ð\8dì\82ç\82È\82¢\82½\82ß\82Ì\91[\92u
341   InSynchronized := false;
342   edtScript.Text := '';
343   edtScript.Color := Pref.BgColor;
344   for i := 0 to SsParser.Count-1 do begin
345     if (SsParser[i] = '\_s') and not InSynchronized then begin
346       InSynchronized := true;
347       if Talked then begin
348         edtScript.SelText := #13#10;
349         Talked := false;
350       end;
351     end else if (SsParser[i] = '\_s') and InSynchronized then begin
352       InSynchronized := false;
353       if Talked then begin
354         edtScript.SelText := #13#10;
355         Talked := false;
356       end;
357     end;
358     if (SsParser[i] = '\u') and not UnyuTalking then begin
359       UnyuTalking := true;
360       if Talked then begin
361         edtScript.SelText := #13#10;
362         Talked := false;
363       end;
364     end;
365     if (SsParser[i] = '\h') and UnyuTalking then begin
366       UnyuTalking := false;
367       if Talked then begin
368         edtScript.SelText := #13#10;
369         Talked := false;
370       end;
371     end;
372     if SsParser.MarkUpType[i] = mtStr then begin
373       if InSynchronized then
374         edtScript.SelAttributes.Color := Pref.TalkColorS
375       else if UnyuTalking then
376         edtScript.SelAttributes.Color := Pref.TalkColorU
377       else
378         edtScript.SelAttributes.Color := Pref.TalkColorH;
379       edtScript.SelText := SsParser[i];
380       Talked := true;
381     end;
382     if SsParser.MarkUpType[i] = mtMeta then begin
383       edtScript.SelAttributes.Color := Pref.MetaWordColor;
384       edtScript.SelText := SsParser[i];
385       Talked := true;
386     end;
387   end;
388 end;
389
390 procedure TfrmLog.lvwLogKeyPress(Sender: TObject; var Key: Char);
391 begin
392   if Key = #13 then lvwLogDblClick(Sender);
393 end;
394
395 procedure TfrmLog.CreateParams(var Params: TCreateParams);
396 begin
397   inherited;
398   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
399 end;
400
401 procedure TfrmLog.lvwLogClick(Sender: TObject);
402 begin
403   //\89E\83N\83\8a\83b\83N\82Å\83\81\83j\83\85\81[\8fo\82·\82Æ\82«\82É\94­\90\82·\82é\95s\8bï\8d\87\91Î\8dô
404   with lvwLog do
405     Selected := Selected;
406 end;
407
408 procedure TfrmLog.lvwLogColumnClick(Sender: TObject; Column: TListColumn);
409 var SortType: TBottleLogSortType;
410     SelectedMID: String;
411     SortColumn: integer;
412 begin
413   if lvwLog.Selected <> nil then
414     SelectedMID := SelectedBottleLog.Bottles[lvwLog.Selected.Index].MID;
415
416   SortColumn := Column.Index;
417   case SortColumn-1 of
418     -1: SortType := stLogTime;
419     subChannel: SortType := stChannel;
420     subGhost:   SortType := stGhost;
421     subVotes:   SortType := stVote;
422     subAgrees:  SortType := stAgree;
423     subScript:  SortType := stScript;
424   else SortType := stLogTime;
425   end;
426
427   SelectedBottleLog.SortBottles(SortType);
428   lvwLog.Invalidate;
429   SelAndFocusMessage(SelectedMID);
430 end;
431
432
433 procedure TfrmLog.mnPopUpCopyScriptClick(Sender: TObject);
434 var
435   Log: TLogItem;
436   Clip: TClipBoard;
437 begin
438   Log := SelectedBottleLog.Bottles[frmLog.lvwLog.Selected.Index];
439   if Log = nil then Exit;
440   Clip := ClipBoard();
441   Clip.SetTextBuf(PChar(Log.Script));
442 end;
443
444 procedure TfrmLog.SetBottleState(const MID: String; State: TLogState);
445 var i: integer;
446     Bottle: TLogItem;
447 begin
448   for i := 0 to FBottleLogList.Count-1 do begin
449     Bottle := (FBottleLogList[i] as TBottleLogList).Bottle(MID);
450     if Bottle <> nil then begin
451       Bottle.State := State;
452       lvwLog.OnChange := nil;
453       lvwLog.Invalidate;
454       lvwLog.OnChange := lvwLogChange;
455     end;
456   end;
457 end;
458
459 procedure TfrmLog.mnSaveLogClick(Sender: TObject);
460 begin
461   if SelectedBottleLog = nil then Exit;
462   SaveDialog.FileName := GetDefaultFileName(SelectedBottleLog.Title, '.log');
463   SaveDialog.InitialDir := ExtractFileDir(Application.ExeName);
464   SaveDialog.DefaultExt := 'log';
465   SaveDialog.FilterIndex := 1;
466   if SaveDialog.Execute then
467     SelectedBottleLog.SaveToSstpLog(SaveDialog.FileName, false);
468 end;
469
470 procedure TfrmLog.mnSaveLogChannelClick(Sender: TObject);
471 begin
472   if SelectedBottleLog = nil then Exit;
473   SaveDialog.FileName := GetDefaultFileName(SelectedBottleLog.Title, '.log');
474   SaveDialog.InitialDir := ExtractFileDir(Application.ExeName);
475   SaveDialog.DefaultExt := 'log';
476   SaveDialog.FilterIndex := 1;
477   if SaveDialog.Execute then
478     SelectedBottleLog.SaveToSstpLog(SaveDialog.FileName, true);
479 end;
480
481 procedure TfrmLog.mnSaveLogScriptClick(Sender: TObject);
482 begin
483   if SelectedBottleLog = nil then Exit;
484   SaveDialog.FileName := GetDefaultFileName(SelectedBottleLog.Title, '.txt');
485   SaveDialog.InitialDir := ExtractFileDir(Application.ExeName);
486   SaveDialog.DefaultExt := 'txt';
487   SaveDialog.FilterIndex := 2;
488   if SaveDialog.Execute then
489     SelectedBottleLog.SaveToText(SaveDialog.FileName);
490 end;
491
492 procedure TfrmLog.mnSaveLogXMLClick(Sender: TObject);
493 begin
494   if SelectedBottleLog = nil then Exit;
495   SaveDialog.FileName := GetDefaultFileName(SelectedBottleLog.Title, '.xml');
496   SaveDialog.InitialDir := ExtractFileDir(Application.ExeName);
497   SaveDialog.DefaultExt := 'xml';
498   SaveDialog.FilterIndex := 3;
499   if SaveDialog.Execute then
500     SelectedBottleLog.SaveToXmlFile(SaveDialog.FileName);
501 end;
502
503 procedure TfrmLog.lvwLogData(Sender: TObject; Item: TListItem);
504 var i: integer;
505     Log: TLogItem;
506 begin
507   if Item = nil then Exit;
508   i := Item.Index;
509   Log := SelectedBottleLog.Bottles[i];
510   with Item do begin
511     Caption := FormatDateTime('yy/mm/dd hh:nn:ss', Log.LogTime);
512     SubItems.Clear;
513     SubItems.Add(Log.Channel);
514     SubItems.Add(Log.Ghost);
515     if Log.LogType = ltBottle then begin
516       if Log.Votes > 0 then
517         SubItems.Add(IntToStr(Log.Votes))
518       else
519         SubItems.Add('');
520       if Log.Agrees > 0 then
521         SubItems.Add(IntToStr(Log.Agrees))
522       else
523         SubItems.Add('');
524     end else begin
525       // \83V\83X\83e\83\80\83\8d\83O\82È\82Ç\82Í\93\8a\95[\81E\93¯\88Ó\82ð\95\\8e¦\82µ\82È\82¢
526       SubItems.Add('');
527       SubItems.Add('');
528     end;
529     SubItems.Add(Log.Script);
530
531     if Log.LogType = ltBottle then begin
532       case Log.State of
533         lsUnopened: ImageIndex := IconBottle;
534         lsPlaying:  ImageIndex := IconPlaying;
535         lsOpened:   ImageIndex := IconOpened;
536       end;
537     end else
538       ImageIndex := IconSystemLog;
539   end;
540 end;
541
542 procedure TfrmLog.UpdateWindow;
543 var EnabledFlag: boolean;
544 begin
545   if true then begin // ColorScript
546     if lvwLog.Color <> Pref.BgColor then lvwLog.Color := Pref.BgColor;
547     if lvwLog.Font.Color <> Pref.TalkColorH then lvwLog.Font.Color := Pref.TalkColorH;
548   end else begin
549     if lvwLog.Color <> clWindow then lvwLog.Color := clWindow;
550     if lvwLog.Font.Color <> clWindowText then lvwLog.Font.Color := clWindowText;
551   end;
552   if SelectedBottleLog <> nil then begin
553     Caption := '\83\8d\83O - ' + SelectedBottleLog.Title;
554     StatusBar.Panels[0].Text := IntToStr(SelectedBottleLog.Count) + '\8c\8f';
555     lvwLog.Items.Count := SelectedBottleLog.Count;
556   end else begin
557     Caption := '\83\8d\83O';
558     StatusBar.Panels[0].Text := '';
559     StatusBar.Panels[1].Text := '';
560     lvwLog.Items.Count := 0;
561   end;
562
563   EnabledFlag := SelectedBottleLog <> nil;
564   tbtnClear.Enabled := EnabledFlag;
565   tbtnSaveLog.Enabled := EnabledFlag;
566   tbtnFindBottle.Enabled := EnabledFlag;
567
568   lvwLog.Invalidate;
569 end;
570
571 procedure TfrmLog.PopupMenuListViewPopup(Sender: TObject);
572 var Log: TLogItem;
573     Child: TMenuItem;
574     Urls: TStringList;
575     i: integer;
576 begin
577   for i := mnJumpURL.Count-1 downto 0 do begin
578     mnJumpURL.Items[i].Free;
579   end;
580   mnJumpURL.Enabled := false;
581   if lvwLog.Selected = nil then Exit;
582   Log := SelectedBottleLog.Bottles[lvwLog.Selected.Index];
583   if Log = nil then Exit;
584   Urls := TStringList.Create;
585   try
586     ExtractURLs(Log.Script, Urls);
587     for i := 0 to Urls.Count-1 do begin
588       Child := TMenuItem.Create(Self);
589       with Child do begin
590         Caption := Format('(&%d) %s', [i+1, StringReplace(Urls[i], '&', '&&', [rfReplaceAll])]);
591         Tag := i;
592         OnClick := mnURLClick;
593         AutoHotkeys := maManual;
594         mnJumpURL.Add(Child);
595       end;
596     end;
597     mnJumpURL.Enabled := Urls.Count > 0;
598   finally
599     Urls.Free;
600   end;
601 end;
602
603 procedure TfrmLog.mnURLClick(Sender: TObject);
604 var LogItem: TLogItem;
605     URL: String;
606     Urls: TStringList;
607 begin
608   if (lvwLog.Selected = nil) or (SelectedBottleLog = nil) then Exit;
609   LogItem := SelectedBottleLog[lvwLog.Selected.Index] as TLogItem;
610   Urls := TStringList.Create;
611   try
612     ExtractURLs(LogItem.Script, Urls);
613     URL := Urls[(Sender as TMenuItem).Tag];
614     ShellExecute(Handle, 'open', PChar(URL), nil, nil, SW_SHOW);
615   finally
616     Urls.Free;
617   end;
618 end;
619
620 procedure TfrmLog.ExtractURLs(Script: String; Result: TStrings);
621 var i, u, j: integer;
622     s: String;
623 begin
624   Result.Clear;
625   SsParser.InputString := Script;
626   for i := 0 to SsParser.Count-1 do begin
627     if (SsParser.Match(SsParser[i], '\URL%b') > 0) then begin
628       for u := 7 downto 1 do begin
629         if (SsParser.Match(SsParser[i],
630             '\URL%b'+StringReplace(StringOfChar('-', u*2),
631             '-', '%b', [rfReplaceAll]))) > 0 then begin
632           for j := 1 to u do begin
633             s := SsParser.GetParam(SsParser[i], j*2);
634             if Pos('http://', s) > 0 then Result.Add(s);
635           end;
636           Break;
637         end;
638       end;
639       if SsParser.Match(SsParser[i], '\URL%b%b') = 0 then begin //\8aÈ\88Õ\94ÅURL\95Ï\8a·
640         //\8aÈ\88Õ\8c`\8e®\URL\83^\83O\95Ï\8a·
641         s := SsParser.GetParam(SsParser[i], 1);
642         if Pos('http://', s) > 0 then Result.Add(s);
643       end;
644     end;
645   end;
646 end;
647
648 procedure TfrmLog.SelAndFocusMessage(const MID: String);
649 var i: integer;
650     Log: TLogItem;
651 begin
652   for i := 0 to SelectedBottleLog.Count-1 do begin
653     Log := SelectedBottleLog.Items[i] as TLogItem;
654     if Log.MID = MID then begin
655       lvwLog.Items[i].Selected := true;
656       lvwLog.Items[i].Focused := true;
657     end;
658   end;
659 end;
660
661 procedure TfrmLog.lvwLogCustomDrawItem(Sender: TCustomListView;
662   Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
663 begin
664   //
665 end;
666
667 procedure TfrmLog.UpdateScript(const Script: String);
668 begin
669   if Script <> FLastScript then begin
670     if Pref.LogWindowPreviewStyle = psConversation then begin
671       UpdateScriptConversationColor(Script);
672     end else begin
673       UpdateScriptScript(Script);
674     end;
675     SendMessage(edtScript.Handle, EM_LINESCROLL, Low(integer), Low(integer)); //\83X\83N\83\8d\81[\83\8b\96ß\82µ
676     FLastScript := Script;
677   end;
678 end;
679
680 procedure TfrmLog.PopupMenuPreviewStylePopup(Sender: TObject);
681 var i: integer;
682 begin
683   with PopupMenuPreviewStyle do
684     for i := 0 to Items.Count-1 do
685       Items[i].Checked := Items[i].Tag = Ord(Pref.LogWindowPreviewStyle)
686 end;
687
688 procedure TfrmLog.mnPreviewStyleClick(Sender: TObject);
689 var i: integer;
690 begin
691   with PopupMenuPreviewStyle do
692     for i := 0 to Items.Count-1 do
693       Items[i].Checked := (Sender as TMenuItem).Tag = Items[i].Tag;
694   Pref.LogWindowPreviewStyle := TLogWindowPreviewStyle((Sender as TMenuItem).Tag);
695   FLastScript := '';
696   lvwLogChange(self, lvwLog.Selected, ctState);
697 end;
698
699 procedure TfrmLog.UpdateScriptScript(const Script: String);
700 var
701   UnyuTalking, InSynchronized: boolean;
702   i: integer;
703 begin
704   edtScript.Color := Pref.BgColor;
705   SsParser.LeaveEscape := true;
706   SsParser.InputString := Script;
707   edtScript.Text := '';
708   edtScript.SelAttributes.Color := clWindowText;
709   UnyuTalking := false;
710   InSynchronized := false;
711   for i := 0 to SsParser.Count-1 do begin
712     case SsParser.MarkUpType[i] of
713       mtStr: begin
714         if InSynchronized then
715           edtScript.SelAttributes.Color := Pref.TalkColorS
716         else if UnyuTalking then
717           edtScript.SelAttributes.Color := Pref.TalkColorU
718         else
719           edtScript.SelAttributes.Color := Pref.TalkColorH;
720       end;
721       mtTag: begin
722         edtScript.SelAttributes.Color := Pref.MarkUpColor;
723         if SsParser[i] = '\h' then
724           UnyuTalking := false
725         else if SsParser[i] = '\u' then
726           UnyuTalking := true
727         else if SsParser[i] = '\_s' then
728           InSynchronized := not InSynchronized;
729       end;
730       mtMeta:   edtScript.SelAttributes.Color := Pref.MetaWordColor;
731       mtTagErr: edtScript.SelAttributes.Color := Pref.MarkErrorColor;
732     end;
733     edtScript.SelText := SsParser[i];
734     if (SsParser[i] = '\n') and (Pref.LogWindowPreviewStyle = psScriptWithLineBreak) then
735       edtScript.SelText := #13#10;
736   end;
737 end;
738
739 procedure TfrmLog.tbtnPreviewStyleClick(Sender: TObject);
740 var sel: integer;
741 begin
742   sel := Ord(Pref.LogWindowPreviewStyle);
743   sel := sel + 1;
744   if sel > Ord(High(TLogWindowPreviewStyle)) then sel := 0;
745   Pref.LogWindowPreviewStyle := TLogWindowPreviewStyle(sel);
746   FLastScript := '';
747   lvwLogChange(self, lvwLog.Selected, ctState);
748 end;
749
750 function TfrmLog.SelectedBottleLog: TBottleLogList;
751 begin
752   if tabBottleLog.TabIndex >= 0 then
753     Result := FBottleLogList.Items[tabBottleLog.TabIndex] as TBottleLogList
754   else
755     Result := nil;
756 end;
757
758 procedure TfrmLog.tabBottleLogChange(Sender: TObject);
759 begin
760   UpdateWindow;
761   if SelectedBottleLog.SelectedIndex >= 0 then begin
762     lvwLog.Items[SelectedBottleLog.SelectedIndex].Selected := true;
763     if lvwLog.Focused then lvwLog.Selected.Focused := true;
764   end;
765   lvwLogChange(Self, nil, ctState);
766 end;
767
768 procedure TfrmLog.LogLoaded(Sender: TObject);
769 begin
770   if SelectedBottleLog = Sender then begin
771     UpdateWindow;
772   end;
773 end;
774
775 procedure TfrmLog.UpdateTab;
776 var i, cur: integer;
777 begin
778   cur := tabBottleLog.tabIndex;
779   tabBottleLog.Tabs.Clear;
780   for i := 0 to FBottleLogList.Count - 1 do begin
781     tabBottleLog.Tabs.Add((FBottleLogList[i] as TBottleLogList).Title);
782   end;
783   if FBottleLogList.Count > 0 then begin
784     if cur < FBottleLogList.Count then
785       tabBottleLog.TabIndex := cur
786     else
787       tabBottleLog.TabIndex := FBottleLogList.Count-1;
788   end;
789 end;
790
791 procedure TfrmLog.LogLoadFailure(Sender: TObject; const Message: String);
792 begin
793   Beep;
794   ShowMessage(Message);
795   if Sender = SelectedBottleLog then UpdateWindow;
796 end;
797
798 procedure TfrmLog.AgreeLog(const MID: String; const Agree: integer);
799 var i: integer;
800     flag: boolean;
801 begin
802   flag := false;
803   for i := 0 to FBottleLogList.Count - 1 do begin
804     if (FBottleLogList[i] as TBottleLogList).Bottle(MID) <> nil then begin
805       (FBottleLogList[i] as TBottleLogList).Bottle(MID).Agrees := Agree;
806       flag := true;
807     end;
808   end;
809   if flag then lvwLog.Invalidate;
810 end;
811
812 procedure TfrmLog.VoteLog(const MID: String; const Vote: integer);
813 var i: integer;
814     flag: boolean;
815 begin
816   flag := false;
817   for i := 0 to FBottleLogList.Count - 1 do begin
818     if (FBottleLogList[i] as TBottleLogList).Bottle(MID) <> nil then begin
819       (FBottleLogList[i] as TBottleLogList).Bottle(MID).Votes := Vote;
820       flag := true;
821     end;
822   end;
823   if flag then lvwLog.Invalidate;
824 end;
825
826 procedure TfrmLog.tabBottleLogChanging(Sender: TObject;
827   var AllowChange: Boolean);
828 begin
829   // \8c»\8dÝ\91I\91ð\82³\82ê\82Ä\82¢\82é\83\8d\83O\82Ì\91I\91ð\8fó\91Ô\82ð\95Û\91
830   if SelectedBottleLog = nil then Exit;
831   if lvwLog.Selected <> nil then
832     SelectedBottleLog.SelectedIndex := lvwLog.Selected.Index
833   else
834     SelectedBottleLog.SelectedIndex := -1;
835 end;
836
837 procedure TfrmLog.tabBottleLogContextPopup(Sender: TObject;
838   MousePos: TPoint; var Handled: Boolean);
839 begin
840   with tabBottleLog do begin
841     Tag := IndexOfTabAt(MousePos.X, MousePos.Y);
842     if Tag < 0 then Handled := true;
843   end;
844 end;
845
846 procedure TfrmLog.mnCloseTabClick(Sender: TObject);
847 begin
848   FBottleLogList.Delete(tabBottleLog.Tag);
849   UpdateTab;
850   UpdateWindow;
851   lvwLogChange(Self, nil, ctState);
852 end;
853
854 procedure TfrmLog.tbtnFindBottleClick(Sender: TObject);
855 var Query: String;
856     ResultLog: TBottleLogList;
857     Item1, Item2: TLogItem;
858     i, matched: integer;
859 begin
860   if SelectedBottleLog = nil then Exit;
861   if SelectedBottleLog.Count = 0 then begin
862     ShowMessage('\8c\9f\8dõ\91Î\8fÛ\82ª\8bó\82Å\82·\81B');
863     Exit;
864   end;
865   Query := '';
866   matched := 0;
867   if InputQuery('\83X\83N\83\8a\83v\83g\96{\95\82ð\8c\9f\8dõ', '\8c\9f\8dõ\95\8e\9a\97ñ', Query) then begin
868     if Query = '' then Exit;
869     ResultLog := TBottleLogList.Create('\8c\9f\8dõ\8c\8b\89Ê');
870     for i := 0 to SelectedBottleLog.Count-1 do begin
871       Item1 := SelectedBottleLog.Items[i] as TLogItem;
872       if AnsiContainsText(Item1.Script, Query) and (Item1.LogType = ltBottle) then begin
873         matched := matched + 1;
874         Item2 := TLogItem.Create(ltBottle, Item1.MID, Item1.Channel,
875           Item1.Script, Item1.Ghost, Item1.LogTime);
876         Item2.State := lsOpened;
877         Item2.Votes := Item1.Votes;
878         Item2.Agrees := Item1.Agrees;
879         ResultLog.Add(Item2);
880       end;
881     end;
882     if matched = 0 then
883       ResultLog.AddSystemLog('\8c©\82Â\82©\82è\82Ü\82¹\82ñ\82Å\82µ\82½');
884     BottleLogList.Add(ResultLog);
885     UpdateTab;
886     tabBottleLog.TabIndex := BottleLogList.Count-1;
887     UpdateWindow;
888   end;
889 end;
890
891 procedure TfrmLog.tbtnOpenLogClick(Sender: TObject);
892 var BottleLog: TBottleLogList;
893     i, Index: integer;
894 begin
895   Index := -1;
896   if OpenDialog.Execute then begin
897     for i := 0 to OpenDialog.Files.Count-1 do begin
898       BottleLog := TBottleLogList.Create(ExtractFileName(OpenDialog.Files[i]));
899       try
900         BottleLog.LoadFromXMLFile(OpenDialog.Files[i]);
901       except
902         on E: EXMLFileOpenException do begin
903           Beep;
904           ShowMessage(E.Message);
905           FreeAndNil(BottleLog);
906         end;
907       end;
908       if BottleLog <> nil then Index := BottleLogList.Add(BottleLog); // \8dÅ\8cã\82É\8aJ\82¢\82½\83\8d\83O\82Ì\88Ê\92u\82ð\8bL\89¯
909     end;
910     UpdateTab;
911     if Index >= 0 then tabBottleLog.TabIndex := Index;
912     UpdateWindow;
913   end;
914 end;
915
916 function TfrmLog.GetDefaultFileName(const Name, Ext: String): String;
917 begin
918   Result := StringReplace(Name, '/', '', [rfReplaceAll]);
919   Result := StringReplace(Result, ' ', '', [rfReplaceAll]);
920   Result := ChangeFileExt(Result, Ext);
921 end;
922
923 function TfrmLog.BottleLogTitled(const LogName: String): TBottleLogList;
924 var i: integer;
925 begin
926   for i := 0 to FBottleLogList.Count-1 do begin
927     if (FBottleLogList[i] as TBottleLogList).Title = LogName then begin
928       Result := (FBottleLogList[i] as TBottleLogList);
929       Exit;
930     end;
931   end;
932   // \8c©\82Â\82©\82ç\82È\82¢\8fê\8d\87
933   Result := TBottleLogList.Create(LogName); // \90V\82µ\82­\8dì\82é
934   FBottleLogList.Add(Result);
935   UpdateTab;
936   if FBottleLogList.Count = 1 then tabBottleLog.TabIndex := 0;
937 end;
938
939 procedure TfrmLog.AllBottleOpened;
940 var i, j: integer;
941     Log: TBottleLogList;
942 begin
943   for i := 0 to FBottleLogList.Count-1 do begin
944     Log  := FBottleLogList[i] as TBottleLogList;
945     for j := 0 to Log.Count-1 do begin
946       Log.Bottles[j].State := lsOpened;
947     end;
948   end;
949 end;
950
951 procedure TfrmLog.tabBottleLogMouseDown(Sender: TObject;
952   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
953 var Index: integer;
954 begin
955   with tabBottleLog do begin
956     Index := IndexOfTabAt(X, Y);
957     if Index = -1 then Exit; //\83^\83u\82ª\82È\82¢\82Ì\82Å\83h\83\89\83b\83O\82Å\82«\82È\82¢
958     if Button = mbLeft then begin
959       FDragTabIndex := Index; //\83h\83\89\83b\83O\82·\82é\83^\83u\82Ì\83C\83\93\83f\83b\83N\83X\82ð\95Û\91
960       BeginDrag(False);
961       FDragTabDest := -1;     //\83h\83\89\83b\83O\98g\90ü\95`\89æ\83t\83\89\83O\83N\83\8a\83A\82Ì\82½\82ß
962     end;
963   end;
964 end;
965
966 procedure TfrmLog.tabBottleLogDragOver(Sender, Source: TObject; X,
967   Y: Integer; State: TDragState; var Accept: Boolean);
968 var TargetRect: TRect;
969     OldDest: integer;
970 begin
971   Accept := Source = tabBottleLog;
972   if not Accept then Exit;
973   with tabBottleLog do begin
974     OldDest := FDragTabDest;
975     FDragTabDest := IndexOfTabAt(X, Y);
976     if FDragTabDest = -1 then begin
977       Accept := false; //\82±\82Ì\8fê\8d\87\82Í\83h\83\8d\83b\83v\82ð\94F\82ß\82È\82¢
978       Exit;
979     end;
980     with Canvas do begin
981       Pen.Mode := pmNot;
982       Pen.Width := 3;
983     end;
984     if (OldDest <> FDragTabDest) and (OldDest >= 0) then begin
985       //\88È\91O\82Ì\98g\90ü\8fÁ\8b\8e
986       TargetRect := TabRect(OldDest);
987       with Canvas do begin
988         Brush.Style := bsClear;
989         Rectangle(TargetRect.Left, TargetRect.Top,
990                   TargetRect.Right, TargetRect.Bottom);
991       end;
992     end;
993     if (OldDest <> FDragTabDest) then begin
994       //\90V\82µ\82¢\98g\90ü\95`\89æ
995       TargetRect := TabRect(FDragTabDest);
996       with Canvas do begin
997         Brush.Style := bsClear;
998         Rectangle(TargetRect.Left, TargetRect.Top,
999                   TargetRect.Right, TargetRect.Bottom);
1000       end;
1001     end;
1002   end;
1003 end;
1004
1005 procedure TfrmLog.tabBottleLogDragDrop(Sender, Source: TObject; X,
1006   Y: Integer);
1007 var DestIndex: integer;
1008 begin
1009   with tabBottleLog do begin
1010     DestIndex := IndexOfTabAt(X, Y);
1011     Tabs.Move(FDragTabIndex, DestIndex);
1012     FBottleLogList.Move(FDragTabIndex, DestIndex);
1013   end;
1014 end;
1015
1016 procedure TfrmLog.tabBottleLogEndDrag(Sender, Target: TObject; X,
1017   Y: Integer);
1018 begin
1019   //\8b­\90§\93I\82É\83^\83u\82ð\8dÄ\95`\89æ\82³\82¹\82é\81B\98g\90ü\8fÁ\82µ\91Î\8dô
1020   tabBottleLog.Tabs.BeginUpdate;
1021   tabBottleLog.Tabs.EndUpdate;
1022 end;
1023
1024 procedure TfrmLog.LogLoadWork(Sender: TObject);
1025 begin
1026   if Sender = SelectedBottleLog then lvwLog.Invalidate;
1027 end;
1028
1029 procedure TfrmLog.lvwLogDrawItem(Sender: TCustomListView; Item: TListItem;
1030   Rect: TRect; State: TOwnerDrawState);
1031 var
1032   DestRect: TRect;
1033   Script: String;
1034   Ico: TIcon;
1035   sub, Ex: integer;
1036 begin
1037   // \94w\8ci\8fÁ\8b\8e
1038   ListView_GetItemRect(lvwLog.Handle, Item.Index, DestRect, LVIR_BOUNDS);
1039
1040   lvwLog.Canvas.Brush.Style := bsSolid;
1041   if Item.Selected then begin
1042     lvwLog.Canvas.Brush.Color := clHighlight
1043   end else begin
1044     lvwLog.Canvas.Brush.Color := Pref.BgColor;
1045   end;
1046   lvwLog.Canvas.FillRect(DestRect);
1047   lvwLog.Canvas.Brush.Style := bsClear;
1048   if Item.Focused and lvwLog.Focused then
1049     lvwLog.Canvas.DrawFocusRect(DestRect);
1050
1051   if Item.Selected then
1052     lvwLog.Canvas.Font.Color := clHighlightText
1053   else
1054     lvwLog.Canvas.Font.Color := Pref.TalkColorH;
1055   lvwLog.Canvas.Refresh;
1056
1057
1058   // \83L\83\83\83v\83V\83\87\83\93(\93ú\95t)
1059   ListView_GetItemRect(lvwLog.Handle, Item.Index, DestRect, LVIR_LABEL);
1060   Inc(DestRect.Left, 2);
1061   Inc(DestRect.Top, 2);
1062   Dec(DestRect.Right, 2);
1063   DrawTextEx(lvwLog.Canvas.Handle, PChar(Item.Caption), -1, DestRect,
1064     DT_SINGLELINE or DT_END_ELLIPSIS, nil);
1065   ListView_GetItemRect(lvwLog.Handle, Item.Index, DestRect, LVIR_ICON);
1066   Ico := TIcon.Create;
1067   try
1068     lvwLog.SmallImages.GetIcon(Item.ImageIndex, Ico);
1069     lvwLog.Canvas.Draw(DestRect.Left, DestRect.Top, Ico);
1070   finally
1071     Ico.Free;
1072   end;
1073   
1074   // \83L\83\83\83v\83V\83\87\83\93\88È\8aO
1075   for sub := 0 to Item.SubItems.Count-1 do
1076   begin
1077     if sub = SubScript then Continue;
1078     ListView_GetSubItemRect(lvwLog.Handle, Item.Index, sub + 1,
1079       LVIR_BOUNDS, @DestRect);
1080     Inc(DestRect.Left, 2);
1081     Inc(DestRect.Top, 2);
1082     Dec(DestRect.Right, 2);
1083     if lvwLog.Columns[sub+1].Alignment = taRightJustify then
1084       Ex := DT_SINGLELINE or DT_END_ELLIPSIS or DT_RIGHT
1085     else
1086       Ex := DT_SINGLELINE or DT_END_ELLIPSIS;
1087     DrawTextEx(lvwLog.Canvas.Handle, PChar(Item.SubItems[sub]), -1, DestRect,
1088       Ex, nil);
1089   end;
1090
1091   // \83X\83N\83\8a\83v\83g
1092   ListView_GetSubItemRect(lvwLog.Handle, Item.Index, SubScript + 1,
1093     LVIR_BOUNDS, @DestRect);
1094   Script := Item.SubItems[SubScript];
1095   DrawSingleLineScript(Script, DestRect, Item);
1096 end;
1097
1098 procedure TfrmLog.DrawSingleLineScript(const Script: String;
1099   const Rect: TRect; Item: TListItem);
1100 var
1101   i, x, w: integer;
1102   UnyuTalking, Synchronized, Spaced: boolean;
1103   Mark: TSsMarkUpType;
1104   procedure ScopeChange;
1105   begin
1106     if (not Spaced) and (Pref.LogListPreviewStyle = psTagStripped) then
1107     begin
1108       Inc(x, 10);
1109       Spaced := true;
1110     end;
1111   end;
1112 begin
1113   SsParser.InputString := Script;
1114   x := 6;
1115   UnyuTalking := false;
1116   Synchronized := false;
1117   Spaced := true; // \83^\83O\8fÈ\97ª\95\\8e¦\8e\9e\82É\95s\95K\97v\82É\83X\83R\81[\83v\95Ï\8a·\8e\9e\82Ì\83X\83y\81[\83X\82ð\8bó\82¯\82È\82¢
1118                   // \82½\82ß\82Ì\83t\83\89\83O
1119   for i := 0 to SsParser.Count - 1 do begin
1120     if SsParser[i] = '\h' then
1121     begin
1122       UnyuTalking := false;
1123       ScopeChange;
1124     end else if SsParser[i] = '\u' then
1125     begin
1126       UnyuTalking := true;
1127       ScopeChange;
1128     end else if SsParser[i] = '\_s' then
1129     begin
1130       Synchronized := not Synchronized;
1131       ScopeChange;
1132     end;
1133     Mark := SsParser.MarkUpType[i];
1134     case Mark of
1135       mtMeta:
1136         begin
1137           lvwLog.Canvas.Font.Color := Pref.MetaWordColor;
1138           Spaced := false;
1139         end;
1140       mtTag:
1141         if Pref.LogListPreviewStyle = psNormal then
1142           lvwLog.Canvas.Font.Color := Pref.MarkUpColor
1143         else
1144         begin
1145           Continue;
1146         end;
1147       mtTagErr:
1148         lvwLog.Canvas.Font.Color := Pref.MarkErrorColor;
1149       else begin
1150         Spaced := false;
1151         if Synchronized then
1152           lvwLog.Canvas.Font.Color := Pref.TalkColorS
1153         else if UnyuTalking then
1154           lvwLog.Canvas.Font.Color := Pref.TalkColorU
1155         else
1156           lvwLog.Canvas.Font.Color := Pref.TalkColorH;
1157       end;
1158     end;
1159     if Item.Selected then lvwLog.Canvas.Font.Color := clHighlightText;
1160     lvwLog.Canvas.Refresh;
1161     w := lvwLog.Canvas.TextWidth(SsParser[i]);
1162     lvwLog.Canvas.TextRect(Rect, Rect.Left + x, Rect.Top + 2, SsParser[i]);
1163     x := x + w;
1164     if Rect.Right - Rect.Left < x then Break;
1165   end;
1166 end;
1167
1168 procedure TfrmLog.mnListPreviewStyleTagStrippedClick(Sender: TObject);
1169 var i: integer;
1170 begin
1171   with PopupMenuListPreviewStyle do
1172     for i := 0 to Items.Count-1 do
1173       Items[i].Checked := (Sender as TMenuItem).Tag = Items[i].Tag;
1174   Pref.LogListPreviewStyle := TLogListPreviewStyle((Sender as TMenuItem).Tag);
1175   lvwLog.Invalidate;
1176 end;
1177
1178 procedure TfrmLog.tbtnListPreviewStyleClick(Sender: TObject);
1179 var sel: integer;
1180 begin
1181   sel := Ord(Pref.LogListPreviewStyle);
1182   sel := sel + 1;
1183   if sel > Ord(High(TLogListPreviewStyle)) then sel := 0;
1184   Pref.LogListPreviewStyle := TLogListPreviewStyle(sel);
1185   lvwLog.Invalidate;
1186 end;
1187
1188 procedure TfrmLog.PopupMenuListPreviewStylePopup(Sender: TObject);
1189 var i: integer;
1190 begin
1191   with PopupMenuListPreviewStyle do
1192     for i := 0 to Items.Count-1 do
1193       Items[i].Checked := Items[i].Tag = Ord(Pref.LogListPreviewStyle)
1194 end;
1195
1196 end.