summaryrefslogtreecommitdiff
path: root/UViewer.pas
diff options
context:
space:
mode:
Diffstat (limited to 'UViewer.pas')
-rw-r--r--UViewer.pas451
1 files changed, 451 insertions, 0 deletions
diff --git a/UViewer.pas b/UViewer.pas
new file mode 100644
index 0000000..d7d1c4c
--- /dev/null
+++ b/UViewer.pas
@@ -0,0 +1,451 @@
+(*
+ Tux Commander - UViewer - Internal viewer
+ Copyright (C) 2008 Tomas Bzatek <tbzatek@users.sourceforge.net>
+ Check for updates on tuxcmd.sourceforge.net
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ WARNING: This is highly experimental feature, use with caution!
+*)
+unit UViewer;
+
+interface
+
+uses
+ glib2, gdk2, gtk2, pango,
+ SysUtils, Types, Classes, Variants, GTKControls, GTKForms, GTKUtils, GTKDialogs, GTKPixbuf, GTKClasses, GTKExtCtrls, GTKConsts,
+ GTKText;
+
+type
+ TFViewer = class(TGTKForm)
+// FDrawingArea: TGTKControl;
+ TextView: TGTKTextView;
+ ScrolledWindow: TGTKScrolledWindow;
+ procedure FormCreate(Sender: TObject); override;
+ procedure FormDestroy(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure FormKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+// procedure DrawingAreaKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+ procedure TextViewKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+ private
+// LineHeight, NumLines: integer;
+ LineBuffer: TStringList;
+ protected
+ AThread: TThread;
+ public
+ function LoadFile(FileName: string): boolean;
+ end;
+
+ TViewerThread = class(TThread)
+ private
+// procedure DoIt;
+ protected
+ procedure Execute; override;
+ public
+ AViewer: TFViewer;
+ constructor Create(Parent: TComponent);
+ destructor Destroy; override;
+ function LoadFile(FileName: string): boolean;
+ end;
+
+var
+ FViewer: TFViewer;
+
+implementation
+
+uses UCoreUtils, UCoreClasses, UConfig, DateUtils, Libc;
+
+
+
+// function expose_event_callback(AWidget: PGtkWidget; event: PGdkEventExpose; data: gpointer): gboolean; cdecl; forward;
+function scroll_event_callback(widget: PGtkWidget; event: PGdkEventScroll; user_data: gpointer): gboolean; cdecl; forward;
+
+
+procedure TFViewer.FormCreate(Sender: TObject);
+begin
+ SetDefaultSize(700, 500);
+ Caption := 'TuxView';
+ BorderWidth := 5;
+ AThread := nil;
+
+ ScrolledWindow := TGTKScrolledWindow.Create(Self);
+ ScrolledWindow.HorizScrollBarPolicy := sbAutomatic;
+ ScrolledWindow.VertScrollBarPolicy := sbAutomatic;
+ ScrolledWindow.ShadowType := stShadowIn;
+ g_signal_connect(G_OBJECT(ScrolledWindow.FWidget), 'scroll-event', G_CALLBACK (@scroll_event_callback), Self);
+ AddControl(ScrolledWindow);
+// ClientArea.AddControl(ScrolledWindow);
+
+(*
+ FDrawingArea := TGTKControl.Create(Self);
+ FDrawingArea.FWidget := gtk_drawing_area_new;
+ gtk_widget_set_events(FDrawingArea.FWidget, GDK_EXPOSURE_MASK or GDK_BUTTON_PRESS_MASK or GDK_POINTER_MOTION_MASK or GDK_KEY_PRESS_MASK);
+ gtk_widget_set_size_request(FDrawingArea.FWidget, 10000, 40000);
+ g_signal_connect(G_OBJECT(FDrawingArea.FWidget), 'expose_event', G_CALLBACK (@expose_event_callback), Self);
+// g_signal_connect_after(G_OBJECT(FDrawingArea.FWidget), 'key_press_event', G_CALLBACK (@key_press_event_callback), NULL);
+ gtk_widget_set(FDrawingArea.FWidget, 'can_focus', TRUE, 0);
+ gtk_widget_set(FDrawingArea.FWidget, 'can_default', TRUE, 0);
+ gtk_widget_show(FDrawingArea.FWidget);
+ FDrawingArea.OnKeyDown := DrawingAreaKeyDown;
+
+ ScrolledWindow.AddWithViewPort(FDrawingArea);
+ FDrawingArea.SetFocus;
+*)
+
+ TextView := TGTKTextView.Create(Self);
+ TextView.CursorVisible := False;
+ TextView.ReadOnly := True;
+ TextView.OnKeyDown := TextViewKeyDown;
+
+ ScrolledWindow.AddControl(TextView);
+ TextView.SetFocus;
+
+ // ******************
+
+ OnKeyDown := FormKeyDown;
+ OnDestroy := FormDestroy;
+ OnClose := FormClose;
+end;
+
+procedure TFViewer.FormKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+begin
+ if Key = GDK_ESCAPE then Close;
+end;
+
+procedure TFViewer.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ Action := caFree;
+ SetParent(nil);
+ if Assigned(FWidget) and GTK_IS_WIDGET(FWidget) then gtk_widget_destroy(PGtkWidget(FWidget));
+// AThread.Terminate;
+// ModalResult := mbOK;
+end;
+
+procedure TFViewer.FormDestroy(Sender: TObject);
+begin
+ try
+ LineBuffer.Free;
+ except end;
+end;
+
+
+procedure smooth_scroll(adj: PGtkAdjustment; dest_value: Double; PageScroll: boolean);
+var increment, val: Double;
+ i, x: integer;
+ timer: PGTimer;
+ microseconds: gulong;
+ dur, st: integer;
+begin
+ if gtk_adjustment_get_value(adj) = dest_value then Exit;
+ if not ConfUseSmoothScrolling then begin
+ gtk_adjustment_set_value(adj, dest_value);
+ Exit;
+ end;
+
+ if not PageScroll then begin
+ dur := SMOOTH_SCROLL_DURATION;
+ st := SMOOTH_SCROLL_STEPS;
+ end else begin
+ dur := SMOOTH_SCROLL_DURATION_PAGE;
+ st := SMOOTH_SCROLL_STEPS_PAGE;
+ end;
+
+ timer := g_timer_new;
+ increment := (dest_value - gtk_adjustment_get_value(adj)) / st;
+ val := gtk_adjustment_get_value(adj);
+
+// DebugMsg(['Start value ', val]);
+ i := 1;
+ x := 0;
+ g_timer_start(timer);
+ repeat
+ g_timer_elapsed(timer, @microseconds);
+ if (microseconds > i*1000*dur / st) and (i < st) then begin
+ val := val + increment;
+ gtk_adjustment_set_value(adj, val);
+// DebugMsg(['Setting value to ', val]);
+ Inc(i);
+ end;
+ gdk_window_process_all_updates;
+ Inc(x);
+ usleep(100);
+ until (microseconds div 1000) > dur;
+ gtk_adjustment_set_value(adj, dest_value);
+ gdk_window_process_all_updates;
+// DebugMsg(['End value ', dest_value]);
+ g_timer_stop(timer);
+
+{ g_timer_elapsed(timer, @microseconds);
+ DebugMsg(['Smooth scroll: required = ', dur, 'ms, elapsed = ', Integer(microseconds div 1000), 'ms, iterations = ', x]); }
+ g_timer_destroy(timer);
+end;
+
+
+procedure TFViewer.TextViewKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+var vadj, hadj: PGtkAdjustment;
+ x: Double;
+begin
+ vadj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(ScrolledWindow.FWidget));
+ hadj := gtk_scrolled_window_get_hadjustment(PGtkScrolledWindow(ScrolledWindow.FWidget));
+// debugmsg(['lower = ', adj^.lower, ', upper = ', adj^.upper, ', value = ', x, ', page_size = ', adj^.page_size]);
+ Accept := False;
+
+ case Key of
+ GDK_HOME: begin
+ smooth_scroll(vadj, 0, True);
+ smooth_scroll(hadj, 0, True);
+ end;
+ GDK_END: begin
+ smooth_scroll(vadj, vadj^.upper - vadj^.page_size, True);
+ end;
+ GDK_Page_Down, GDK_SPACE: begin
+ x := gtk_adjustment_get_value(vadj) + vadj^.page_increment;
+ if x + vadj^.page_size > vadj^.upper then x := vadj^.upper - vadj^.page_size;
+ smooth_scroll(vadj, x, True);
+ end;
+ GDK_Page_Up: begin
+ x := gtk_adjustment_get_value(vadj) - vadj^.page_increment;
+ if x < 0 then x := 0;
+ smooth_scroll(vadj, x, True);
+ end;
+ GDK_Down: begin
+ x := gtk_adjustment_get_value(vadj) + vadj^.step_increment;
+ if x + vadj^.page_size > vadj^.upper then x := vadj^.upper - vadj^.page_size;
+ smooth_scroll(vadj, x, False);
+ end;
+ GDK_Up: begin
+ x := gtk_adjustment_get_value(vadj) - vadj^.step_increment;
+ if x < 0 then x := 0;
+ smooth_scroll(vadj, x, False);
+ end;
+ GDK_Right: begin
+ x := gtk_adjustment_get_value(hadj) + hadj^.step_increment;
+ if x + hadj^.page_size > hadj^.upper then x := hadj^.upper - hadj^.page_size;
+ smooth_scroll(hadj, x, False);
+ end;
+ GDK_Left: begin
+ x := gtk_adjustment_get_value(hadj) - hadj^.step_increment;
+ if x < 0 then x := 0;
+ smooth_scroll(hadj, x, False);
+ end;
+ GDK_W, GDK_Capital_W: if TextView.WrapMode = wmWrapNone then TextView.WrapMode := wmWrapWord
+ else TextView.WrapMode := wmWrapNone;
+ GDK_C, GDK_Capital_C, GDK_Insert: if (ssCtrl in Shift) then Accept := True;
+ GDK_S, GDK_Capital_S: gtk_widget_modify_font(TextView.FWidget, pango_font_description_from_string('Monospace'));
+ GDK_A, GDK_Capital_A: gtk_widget_modify_font(TextView.FWidget, nil);
+
+ end;
+end;
+
+function scroll_event_callback(widget: PGtkWidget; event: PGdkEventScroll; user_data: gpointer): gboolean; cdecl;
+var vadj: PGtkAdjustment;
+ x: Double;
+begin
+ vadj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(TFViewer(user_data).ScrolledWindow.FWidget));
+ Result := True;
+
+ case event^.direction of
+ GDK_SCROLL_UP: begin
+ x := gtk_adjustment_get_value(vadj) - 1.5*vadj^.step_increment;
+ if x < 0 then x := 0;
+ smooth_scroll(vadj, x, False);
+ end;
+ GDK_SCROLL_DOWN: begin
+ x := gtk_adjustment_get_value(vadj) + 1.5*vadj^.step_increment;
+ if x + vadj^.page_size > vadj^.upper then x := vadj^.upper - vadj^.page_size;
+ smooth_scroll(vadj, x, False);
+ end;
+ end;
+end;
+
+
+(*
+procedure TFViewer.DrawingAreaKeyDown(Sender: TObject; Key: Word; Shift: TShiftState; var Accept: boolean);
+var adj: PGtkAdjustment;
+ x: integer;
+begin
+ Accept := True;
+ adj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(ScrolledWindow.FWidget));
+ case Key of
+ GDK_ESCAPE: Close;
+ GDK_Down: begin
+ x := Trunc(gtk_adjustment_get_value(adj)) + LineHeight;
+ if x + Trunc(adj^.page_size) > LineHeight * NumLines then x := LineHeight * NumLines - Trunc(adj^.page_size);
+ gtk_adjustment_set_value(adj, x);
+ end;
+ GDK_Up: begin
+ x := Trunc(gtk_adjustment_get_value(adj)) - LineHeight;
+ if x < 0 then x := 0;
+ gtk_adjustment_set_value(adj, x);
+ end;
+ GDK_space: begin
+ x := Trunc(gtk_adjustment_get_value(adj) + adj^.page_increment);
+ if x + Trunc(adj^.page_size) > LineHeight * NumLines then x := LineHeight * NumLines - Trunc(adj^.page_size);
+ gtk_adjustment_set_value(adj, x);
+ end;
+ end;
+{ if event^.keyval = 65364 then begin // Down
+ adj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(scrolledWindow));
+ x := Trunc(gtk_adjustment_get_value(adj)) + LineHeight;
+ if x + Trunc(adj^.page_size) > LineHeight * NumLines then x := LineHeight * NumLines - Trunc(adj^.page_size);
+ gtk_adjustment_set_value(adj, x);
+ end;
+ if event^.keyval = 65362 then begin // Up
+ adj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(scrolledWindow));
+ x := Trunc(gtk_adjustment_get_value(adj)) - LineHeight;
+ if x < 0 then x := 0;
+ gtk_adjustment_set_value(adj, x);
+ end;
+ if (event^.keyval = 65366) or (event^.keyval = 32) then begin // PageDown, Space
+ adj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(scrolledWindow));
+ x := Trunc(gtk_adjustment_get_value(adj) + adj^.page_increment);
+ if x + Trunc(adj^.page_size) > LineHeight * NumLines then x := LineHeight * NumLines - Trunc(adj^.page_size);
+ gtk_adjustment_set_value(adj, x);
+ end;
+ if event^.keyval = 65365 then begin // PageUp
+ adj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(scrolledWindow));
+ x := Trunc(gtk_adjustment_get_value(adj) - adj^.page_increment);
+ if x < 0 then x := 0;
+ gtk_adjustment_set_value(adj, x);
+ end;
+ if event^.keyval = 65360 then begin // Home
+ adj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(scrolledWindow));
+ gtk_adjustment_set_value(adj, 0);
+ end;
+ if event^.keyval = 65367 then begin // End
+ adj := gtk_scrolled_window_get_vadjustment(PGtkScrolledWindow(scrolledWindow));
+ gtk_adjustment_set_value(adj, LineHeight * NumLines - adj^.page_size);
+ end; }
+end;
+*)
+
+(********************************************************************************************************************************)
+(*
+function expose_event_callback(AWidget: PGtkWidget; event: PGdkEventExpose; data: gpointer): gboolean; cdecl;
+var Layout: PPangoLayout;
+ s: string;
+ i, LineFrom, LineTo: integer;
+var Cursor: PGdkCursor;
+begin
+ // Count the visible lines
+ LineFrom := (event^.area.y div TFViewer(data).LineHeight) - 1;
+ if LineFrom < 0 then LineFrom := 0;
+ LineTo := ((event^.area.y + event^.area.height) div TFViewer(data).LineHeight) + 1;
+// if LineTo > MaxLineNum then LineTo := MaxLineNum;
+
+// DebugMsg(['Rendering lines ', LineFrom, ' - ', LineTo, '; expose_area: [', event^.area.x, ', ', event^.area.y, '] - ', event^.area.width, 'x', event^.area.height]);
+
+
+
+ gdk_draw_rectangle(PGdkDrawable(Awidget^.window), Awidget^.style^.white_gc, Integer(TRUE),
+ event^.area.x, event^.area.y, event^.area.width, event^.area.height);
+
+
+
+ Layout := pango_layout_new(gtk_widget_get_pango_context(Awidget));
+ for i := LineFrom to LineTo do begin
+// s := Format('This is the text on the line %d. Hope the rendering will be fast', [i]);
+ if i < TFViewer(data).LineBuffer.Count
+ then s := {ANSIToUTF8(}TFViewer(data).LineBuffer[i]
+ else s := '';
+ pango_layout_set_text(Layout, PChar(s), Length(PChar(s)));
+ gdk_draw_layout(PGdkDrawable(Awidget^.window), Awidget^.style^.fg_gc[GTK_WIDGET_STATE (Awidget)], 5, i * TFViewer(data).LineHeight, Layout);
+ end;
+ g_object_unref(Layout);
+
+
+( * gdk_draw_arc(PGdkDrawable(Awidget^.window),
+ Awidget^.style^.fg_gc[GTK_WIDGET_STATE (Awidget)],
+ Integer(TRUE),
+ 0, 0, 500, 500, {Awidget^.allocation.width, Awidget^.allocation.height,}
+ 0, 64 * 360);
+* )
+
+ // !!!!!!!!!!!! Toto oddelat (musi se volat asi po Application.ProcessMessages (se mne nechtelo s tim drbat tady))
+ cursor := gdk_cursor_new(152);
+ gdk_window_set_cursor(AWidget^.window, cursor);
+ gdk_cursor_unref(cursor);
+
+ Result := True;
+end;
+*)
+
+function TFViewer.LoadFile(FileName: string): boolean;
+var Valid: boolean;
+ i: integer;
+begin
+ Result := False;
+ try
+ LineBuffer := TStringList.Create;
+ LineBuffer.LoadFromFile(FileName);
+
+ Valid := True;
+ for i := 0 to LineBuffer.Count - 1 do begin
+ Valid := Valid and g_utf8_validate(PChar(LineBuffer[i]), -1, nil);
+ if not Valid then Break;
+ end;
+
+ if Valid then TextView.Lines.SetText(LineBuffer.Text)
+ else
+ for i := 0 to LineBuffer.Count - 1 do
+ TextView.Lines.InsertText(AnsiToUtf8(LineBuffer[i]) + #10);
+
+
+{ LineHeight := 16;
+ NumLines := LineBuffer.Count; }
+ Caption := Format('TuxView [%s]', [ANSIToUTF8(FileName)]);
+// FDrawingArea.SetSizeRequest(-1, NumLines * LineHeight);
+ Result := True;
+ except
+ Exit;
+ end;
+end;
+
+(********************************************************************************************************************************)
+procedure TViewerThread.Execute;
+begin
+ gdk_threads_enter;
+// DoIt;
+ AViewer.Show;
+// AViewer.Run;
+ gdk_threads_leave;
+end;
+
+constructor TViewerThread.Create(Parent: TComponent);
+begin
+ AViewer := TFViewer.Create(Parent);
+ AViewer.AThread := Self;
+ FreeOnTerminate := True;
+ inherited Create(True);
+end;
+
+destructor TViewerThread.Destroy;
+begin
+{ AViewer.Free;
+ inherited Destroy; }
+end;
+
+function TViewerThread.LoadFile(FileName: string): boolean;
+begin
+ Result := AViewer.LoadFile(FileName);
+end;
+
+{procedure TViewerThread.DoIt;
+begin
+ Application.MessageBox('ddd')
+end; }
+
+
+end.