mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-05 16:35:57 +02:00
gtk1,gtk2: improve text cursor drawing.
gtk2: use system settings to determine blink time and use special gtk function to draw text cursor shape (#0011887) git-svn-id: trunk@16152 -
This commit is contained in:
parent
508983cd7e
commit
b494a1f624
@ -86,6 +86,11 @@ function GTK_APIWIDGETCLIENT_TYPE: Guint;
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
CURSOR_ON_MULTIPLIER = 2;
|
||||||
|
CURSOR_OFF_MULTIPLIER = 1;
|
||||||
|
CURSOR_DIVIDER = 3;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// gtk_winapiwindow_internal
|
// gtk_winapiwindow_internal
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -95,14 +100,15 @@ type
|
|||||||
Y: Integer;
|
Y: Integer;
|
||||||
Width: Integer;
|
Width: Integer;
|
||||||
Height: Integer;
|
Height: Integer;
|
||||||
Visible: Boolean; // Caret is on (can be visible/invisible due to Blinking)
|
Visible: Boolean; // Caret is on (can be visible/invisible due to Blinking)
|
||||||
IsDrawn: Boolean; // Caret is visible at the moment
|
IsDrawn: Boolean; // Caret is visible at the moment
|
||||||
Blinking: Boolean; // Caret should blink
|
Blinking: Boolean; // Caret should blink
|
||||||
|
BlinkTime: Integer; // Blink time = show + hide time
|
||||||
|
BlinkTimeout: Integer; // Time after which if there is no user interaction happened blinking must finish
|
||||||
BlinkHide: boolean; // current blinking phase is Hide
|
BlinkHide: boolean; // current blinking phase is Hide
|
||||||
Pixmap: PGDKPixMap;
|
Pixmap: PGDKPixMap;
|
||||||
BackPixmap: PGDKPixMap;
|
BackPixmap: PGDKPixMap;
|
||||||
Timer: guint;
|
Timer: guint;
|
||||||
TimerInterval: guint32;
|
|
||||||
ShowHideOnFocus: boolean; // true = hide on loose focus, show on get focus
|
ShowHideOnFocus: boolean; // true = hide on loose focus, show on get focus
|
||||||
Invalidated: boolean;
|
Invalidated: boolean;
|
||||||
end;
|
end;
|
||||||
@ -225,6 +231,9 @@ procedure GTKAPIWidgetClient_SetCaretRespondToFocus(Client: PGTKAPIWidgetClient;
|
|||||||
procedure GTKAPIWidgetClient_GetCaretRespondToFocus(Client: PGTKAPIWidgetClient;
|
procedure GTKAPIWidgetClient_GetCaretRespondToFocus(Client: PGTKAPIWidgetClient;
|
||||||
var ShowHideOnFocus: boolean); forward;
|
var ShowHideOnFocus: boolean); forward;
|
||||||
|
|
||||||
|
function GTKAPIWidgetClient_GetCursorBlink(Client: PGTKAPIWidgetClient): gboolean; forward;
|
||||||
|
function GTKAPIWidgetClient_GetCursorBlinkTime(Client: PGTKAPIWidgetClient): gint; forward;
|
||||||
|
function GTKAPIWidgetClient_GetCursorBlinkTimeout(Client: PGTKAPIWidgetClient): gint; forward;
|
||||||
//-----------------------------
|
//-----------------------------
|
||||||
|
|
||||||
procedure GTKAPIWidget_SetShadowType(APIWidget: PGTKAPIWidget;
|
procedure GTKAPIWidget_SetShadowType(APIWidget: PGTKAPIWidget;
|
||||||
@ -336,7 +345,9 @@ begin
|
|||||||
begin
|
begin
|
||||||
Visible := False;
|
Visible := False;
|
||||||
IsDrawn := False;
|
IsDrawn := False;
|
||||||
Blinking := True;
|
Blinking := GTKAPIWidgetClient_GetCursorBlink(PGTKAPIWidgetClient(Client));
|
||||||
|
BlinkTime := GTKAPIWidgetClient_GetCursorBlinkTime(PGTKAPIWidgetClient(Client));
|
||||||
|
BlinkTimeout := GTKAPIWidgetClient_GetCursorBlinkTimeout(PGTKAPIWidgetClient(Client));
|
||||||
X := 0;
|
X := 0;
|
||||||
Y := 0;
|
Y := 0;
|
||||||
Width := 1;
|
Width := 1;
|
||||||
@ -471,10 +482,10 @@ begin
|
|||||||
|
|
||||||
//@ gtk_widget_set_flags(AWidget, GTK_REALIZED);
|
//@ gtk_widget_set_flags(AWidget, GTK_REALIZED);
|
||||||
|
|
||||||
{$Ifdef GTK2}
|
{$IFNDEF GTK1}
|
||||||
gtk_widget_set_double_buffered(AWidget, True); // True bites caret => ToDo
|
gtk_widget_set_double_buffered(AWidget, True); // True bites caret => ToDo
|
||||||
gtk_widget_set_redraw_on_allocate(AWidget, False);
|
gtk_widget_set_redraw_on_allocate(AWidget, False);
|
||||||
{$EndIf}
|
{$ENDIF}
|
||||||
|
|
||||||
//@ with Attributes do
|
//@ with Attributes do
|
||||||
//@ begin
|
//@ begin
|
||||||
@ -653,8 +664,49 @@ begin
|
|||||||
end;}
|
end;}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure GTKAPIWidgetClient_DrawCaret(Client: PGTKAPIWidgetClient;
|
function GTKAPIWidgetClient_GetCursorBlink(Client: PGTKAPIWidgetClient): gboolean;
|
||||||
CalledByTimer: boolean);
|
{$ifndef GTK1}
|
||||||
|
var
|
||||||
|
settings: PGtkSettings;
|
||||||
|
{$endif}
|
||||||
|
begin
|
||||||
|
{$ifdef GTK1}
|
||||||
|
Result := True;
|
||||||
|
{$else}
|
||||||
|
settings := gtk_widget_get_settings(PGtkWidget(Client));
|
||||||
|
g_object_get(settings, 'gtk-cursor-blink', @Result, nil);
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GTKAPIWidgetClient_GetCursorBlinkTime(Client: PGTKAPIWidgetClient): gint;
|
||||||
|
{$ifndef GTK1}
|
||||||
|
var
|
||||||
|
settings: PGtkSettings;
|
||||||
|
{$endif}
|
||||||
|
begin
|
||||||
|
{$ifdef GTK1}
|
||||||
|
Result := 1200;
|
||||||
|
{$else}
|
||||||
|
settings := gtk_widget_get_settings(PGtkWidget(Client));
|
||||||
|
g_object_get(settings, 'gtk-cursor-blink-time', @Result, nil);
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GTKAPIWidgetClient_GetCursorBlinkTimeout(Client: PGTKAPIWidgetClient): gint;
|
||||||
|
{$ifndef GTK1}
|
||||||
|
var
|
||||||
|
settings: PGtkSettings;
|
||||||
|
{$endif}
|
||||||
|
begin
|
||||||
|
{$ifdef GTK1}
|
||||||
|
Result := $7FFFFFFF;
|
||||||
|
{$else}
|
||||||
|
settings := gtk_widget_get_settings(PGtkWidget(Client));
|
||||||
|
g_object_get(settings, 'gtk-cursor-blink-timeout', @Result, nil);
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure GTKAPIWidgetClient_DrawCaret(Client: PGTKAPIWidgetClient; CalledByTimer: boolean);
|
||||||
{ ShowCaret/HideCaret are used in winapi like:
|
{ ShowCaret/HideCaret are used in winapi like:
|
||||||
ShowCaret (paint xor)
|
ShowCaret (paint xor)
|
||||||
Blinking (restore)
|
Blinking (restore)
|
||||||
@ -689,45 +741,56 @@ procedure GTKAPIWidgetClient_DrawCaret(Client: PGTKAPIWidgetClient;
|
|||||||
Blinking makes it more complicated, because a Hide triggers an OnPaint,
|
Blinking makes it more complicated, because a Hide triggers an OnPaint,
|
||||||
which triggers in synedit code HideCaret+ShowCaret.
|
which triggers in synedit code HideCaret+ShowCaret.
|
||||||
}
|
}
|
||||||
|
{$IFDEF GTK1}
|
||||||
const
|
const
|
||||||
BlinkingInterval = 500;
|
|
||||||
GC_STATE: array[Boolean] of TGtkStateType =
|
GC_STATE: array[Boolean] of TGtkStateType =
|
||||||
(GTK_STATE_INSENSITIVE, GTK_STATE_NORMAL);
|
(
|
||||||
|
GTK_STATE_INSENSITIVE,
|
||||||
|
GTK_STATE_NORMAL
|
||||||
|
);
|
||||||
|
{$ENDIF}
|
||||||
var
|
var
|
||||||
Widget: PGTKWidget;
|
Widget: PGTKWidget;
|
||||||
WidgetStyle: PGTKStyle;
|
WidgetStyle: PGTKStyle;
|
||||||
HasFocus: boolean;
|
HasFocus: boolean;
|
||||||
ForeGroundGC: PGdkGC;
|
|
||||||
WidgetIsPainting: Boolean;
|
WidgetIsPainting: Boolean;
|
||||||
|
{$IFDEF GTK1}
|
||||||
|
ForeGroundGC: PGdkGC;
|
||||||
|
{$ELSE}
|
||||||
|
location: TGdkRectangle;
|
||||||
|
{$ENDIF}
|
||||||
begin
|
begin
|
||||||
if Client = nil then begin
|
if Client = nil then
|
||||||
|
begin
|
||||||
DebugLn('WARNING: [GTKAPIWidgetClient_DrawCaret] Got nil client');
|
DebugLn('WARNING: [GTKAPIWidgetClient_DrawCaret] Got nil client');
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Widget := PGTKWidget(Client);
|
Widget := PGTKWidget(Client);
|
||||||
WidgetStyle := gtk_widget_get_style(Widget);
|
WidgetStyle := gtk_widget_get_style(Widget);
|
||||||
WidgetIsPainting:=GTKAPIWidgetClient_IsPainting(Client);
|
WidgetIsPainting := GTKAPIWidgetClient_IsPainting(Client);
|
||||||
|
|
||||||
with Client^.Caret do
|
with Client^.Caret do
|
||||||
begin
|
begin
|
||||||
HasFocus:=gtk_widget_has_focus(Widget);
|
HasFocus := gtk_widget_has_focus(Widget);
|
||||||
if WidgetIsPainting then
|
if WidgetIsPainting then
|
||||||
Invalidated:=false;
|
Invalidated := false;
|
||||||
|
|
||||||
{$IFDEF VerboseCaret}
|
{$IFDEF VerboseCaret}
|
||||||
DebugLn(['GTKAPIWidgetClient_DrawCaret START Client=',DbgS(Client),' Timer=',Timer,' Blink=',Blinking,' BlinkHide=',BlinkHide,' Visible=',Visible,' ShowHideOnFocus=',ShowHideOnFocus,' Focus=',gtk_widget_has_focus(Widget),' IsDrawn=',IsDrawn,' W=',Width,' H=',Height,' WidgetIsPainting=',WidgetIsPainting]);
|
DebugLn(['GTKAPIWidgetClient_DrawCaret START Client=',DbgS(Client),' Timer=',Timer,' Blink=',Blinking,' BlinkHide=',BlinkHide,' Visible=',Visible,' ShowHideOnFocus=',ShowHideOnFocus,' Focus=',gtk_widget_has_focus(Widget),' IsDrawn=',IsDrawn,' W=',Width,' H=',Height,' WidgetIsPainting=',WidgetIsPainting]);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
|
|
||||||
if IsDrawn
|
if IsDrawn and
|
||||||
and ((not Visible)
|
(
|
||||||
or (Blinking and BlinkHide))
|
(not Visible) or
|
||||||
then begin
|
(Blinking and BlinkHide)
|
||||||
|
) then
|
||||||
|
begin
|
||||||
// hide caret (restore background)
|
// hide caret (restore background)
|
||||||
if WidgetIsPainting then begin
|
if WidgetIsPainting then
|
||||||
if (BackPixmap <> nil)
|
begin
|
||||||
and (Widget<>nil)
|
if (BackPixmap <> nil) and (Widget<>nil) and (WidgetStyle<>nil) then
|
||||||
and (WidgetStyle<>nil)
|
begin
|
||||||
then begin
|
|
||||||
gdk_draw_pixmap(
|
gdk_draw_pixmap(
|
||||||
Widget^.Window,
|
Widget^.Window,
|
||||||
WidgetStyle^.bg_gc[GTK_STATE_NORMAL],
|
WidgetStyle^.bg_gc[GTK_STATE_NORMAL],
|
||||||
@ -741,13 +804,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
IsDrawn := False;
|
IsDrawn := False;
|
||||||
Invalidated:=false;
|
Invalidated:=false;
|
||||||
end else begin
|
end else
|
||||||
|
begin
|
||||||
// paint only during painting, otherwise invalidate
|
// paint only during painting, otherwise invalidate
|
||||||
{$IFDEF VerboseCaret}
|
{$IFDEF VerboseCaret}
|
||||||
DebugLn(['GTKAPIWidgetClient_DrawCaret Invalidate Hide ',X,',',Y]);
|
DebugLn(['GTKAPIWidgetClient_DrawCaret Invalidate Hide ',X,',',Y]);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
GTKAPIWidgetClient_InvalidateCaret(Client);
|
GTKAPIWidgetClient_InvalidateCaret(Client);
|
||||||
IsDrawn:=false;
|
IsDrawn := false;
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -761,8 +825,8 @@ begin
|
|||||||
if Pixmap <> nil then
|
if Pixmap <> nil then
|
||||||
Assert(False, 'Trace:TODO: [GTKAPIWidgetClient_DrawCaret] Implement bitmap');
|
Assert(False, 'Trace:TODO: [GTKAPIWidgetClient_DrawCaret] Implement bitmap');
|
||||||
|
|
||||||
if WidgetIsPainting then begin
|
if WidgetIsPainting then
|
||||||
|
begin
|
||||||
//Create backbitmap if needed
|
//Create backbitmap if needed
|
||||||
if (BackPixmap = nil)
|
if (BackPixmap = nil)
|
||||||
and (Widget^.Window<>nil)
|
and (Widget^.Window<>nil)
|
||||||
@ -805,6 +869,7 @@ begin
|
|||||||
and (Width>0)
|
and (Width>0)
|
||||||
and (Height>0)
|
and (Height>0)
|
||||||
then begin
|
then begin
|
||||||
|
{$ifdef GTK1}
|
||||||
// set draw function to xor
|
// set draw function to xor
|
||||||
ForeGroundGC:=WidgetStyle^.fg_gc[GC_STATE[PtrUInt(Pixmap) <> 1]];
|
ForeGroundGC:=WidgetStyle^.fg_gc[GC_STATE[PtrUInt(Pixmap) <> 1]];
|
||||||
//gdk_gc_get_values(ForeGroundGC,@ForeGroundGCValues);
|
//gdk_gc_get_values(ForeGroundGC,@ForeGroundGCValues);
|
||||||
@ -827,6 +892,14 @@ begin
|
|||||||
// restore draw function
|
// restore draw function
|
||||||
gdk_gc_set_function(ForeGroundGC,GDK_COPY);
|
gdk_gc_set_function(ForeGroundGC,GDK_COPY);
|
||||||
end;
|
end;
|
||||||
|
{$ELSE}
|
||||||
|
location.x := X;
|
||||||
|
location.y := Y - 1;
|
||||||
|
location.width := 0;
|
||||||
|
location.height := Height;
|
||||||
|
gtk_draw_insertion_cursor(Widget, Widget^.Window, nil, @location, true,
|
||||||
|
GTK_TEXT_DIR_LTR, false);
|
||||||
|
{$ENDIF}
|
||||||
end else
|
end else
|
||||||
DebugLn('***: Draw Caret failed: Client=',DbgS(Client),
|
DebugLn('***: Draw Caret failed: Client=',DbgS(Client),
|
||||||
' X='+dbgs(X)+' Y='+dbgs(Y)+' W='+dbgs(Width)+' H='+dbgs(Height),
|
' X='+dbgs(X)+' Y='+dbgs(Y)+' W='+dbgs(Width)+' H='+dbgs(Height),
|
||||||
@ -841,20 +914,26 @@ begin
|
|||||||
GTKAPIWidgetClient_InvalidateCaret(Client);
|
GTKAPIWidgetClient_InvalidateCaret(Client);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// stop, start timer
|
// stop, start timer
|
||||||
if Visible and Blinking
|
if Visible and Blinking and ((not ShowHideOnFocus) or HasFocus) then
|
||||||
and ((not ShowHideOnFocus) or HasFocus)
|
begin
|
||||||
then begin
|
if Timer = 0 then
|
||||||
TimerInterval:=BlinkingInterval;
|
if IsDrawn then
|
||||||
if Timer=0 then begin
|
Timer := gtk_timeout_add(BlinkTime * CURSOR_ON_MULTIPLIER div CURSOR_DIVIDER,
|
||||||
Timer := gtk_timeout_add(TimerInterval, @GTKAPIWidgetClient_Timer, Client);
|
@GTKAPIWidgetClient_Timer, Client)
|
||||||
end;
|
else
|
||||||
end else begin
|
Timer := gtk_timeout_add(BlinkTime * CURSOR_OFF_MULTIPLIER div CURSOR_DIVIDER,
|
||||||
if Timer<>0 then begin
|
@GTKAPIWidgetClient_Timer, Client)
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if Timer <> 0 then
|
||||||
|
begin
|
||||||
gtk_timeout_remove(Timer);
|
gtk_timeout_remove(Timer);
|
||||||
Timer:=0;
|
Timer := 0;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{$IFDEF VerboseCaret}
|
{$IFDEF VerboseCaret}
|
||||||
DebugLn(['GTKAPIWidgetClient_DrawCaret END Client=',DbgS(Client),' Timer=',Timer,' Blink=',Blinking,' BlinkHide=',BlinkHide,' Visible=',Visible,' ShowHideOnFocus=',ShowHideOnFocus,' Focus=',gtk_widget_has_focus(Widget),' IsDrawn=',IsDrawn,' W=',Width,' H=',Height,' WidgetIsPainting=',WidgetIsPainting]);
|
DebugLn(['GTKAPIWidgetClient_DrawCaret END Client=',DbgS(Client),' Timer=',Timer,' Blink=',Blinking,' BlinkHide=',BlinkHide,' Visible=',Visible,' ShowHideOnFocus=',ShowHideOnFocus,' Focus=',gtk_widget_has_focus(Widget),' IsDrawn=',IsDrawn,' W=',Width,' H=',Height,' WidgetIsPainting=',WidgetIsPainting]);
|
||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
@ -1295,7 +1374,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
MParentClass:=nil;
|
MParentClass := nil;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -119,6 +119,8 @@ function gtk_tree_path_new_from_indices(first_index: gint): PGtkTreePath; cdecl;
|
|||||||
procedure gtk_toolbar_insert(toolbar: PGtkToolBar; item: PGtkToolItem; pos: gint); cdecl; external gtklib name 'gtk_toolbar_insert';
|
procedure gtk_toolbar_insert(toolbar: PGtkToolBar; item: PGtkToolItem; pos: gint); cdecl; external gtklib name 'gtk_toolbar_insert';
|
||||||
procedure gtk_event_box_set_visible_window(event_box: PGtkEventBox; visible_window: gboolean); cdecl; external gtklib name 'gtk_event_box_set_visible_window';
|
procedure gtk_event_box_set_visible_window(event_box: PGtkEventBox; visible_window: gboolean); cdecl; external gtklib name 'gtk_event_box_set_visible_window';
|
||||||
procedure gtk_event_box_set_above_child(event_box: PGtkEventBox; visible_window: gboolean); cdecl; external gtklib name 'gtk_event_box_set_above_child';
|
procedure gtk_event_box_set_above_child(event_box: PGtkEventBox; visible_window: gboolean); cdecl; external gtklib name 'gtk_event_box_set_above_child';
|
||||||
|
procedure gtk_draw_insertion_cursor(widget:PGtkWidget; drawable:PGdkDrawable; area:PGdkRectangle; location:PGdkRectangle; is_primary:gboolean;
|
||||||
|
direction:TGtkTextDirection; draw_arrow:gboolean); cdecl; external gtklib;
|
||||||
|
|
||||||
// gtk 2.6
|
// gtk 2.6
|
||||||
type
|
type
|
||||||
|
Loading…
Reference in New Issue
Block a user