📄 box.zc
字号:
//[of]:description
//[c]The base object for the user interface
//[cf]
//[of]:license
//[c]Code Browser - a folding text editor for programmers
//[c]Copyright (C) 2003-07 Marc Kerbiquet
//[c]
//[c]This program is free software; you can redistribute it and/or modify
//[c]it under the terms of the GNU General Public License as published by
//[c]the Free Software Foundation; either version 2 of the License, or
//[c](at your option) any later version.
//[c]
//[c]This program is distributed in the hope that it will be useful,
//[c]but WITHOUT ANY WARRANTY; without even the implied warranty of
//[c]MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//[c]GNU General Public License for more details.
//[c]
//[c]You should have received a copy of the GNU General Public License
//[c]along with this program; if not, write to the Free Software
//[c]Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//[cf]
//[of]:imports
import "base/types"
import "base/memory"
import "base/memory-allocator"
import "collection/linked-collection"
import "text/string"
import "text/string-buffer"
import "text/vector-of-strings"
import "net/uri"
import "file/file"
//[c]
import "graphics/geometry"
import "graphics/graphics"
import "toolbox/clipboard"
import "toolbox/timer"
import "user/keyboard"
import "user/command"
//[c]
import "glib/glib"
import "glib/glib-object"
import "gdk/gdk"
import "gtk/gtk"
import "private/boot"
import "private/sys-graphics"
import "private/sys-command"
//[cf]
//[c]
//[of]:GTK+
//[of]:description
//[c]This part contains GTK+ specific code.
//[c]
//[c]The definitions of this part must only be used by the GTK+ specific
//[c]components.
//[cf]
//[of]:sys drop file event
public struct sys drop files event
list : local vector of strings
end
//[cf]
//[of]:sys box class
//[c]
public struct sys box class
activate: {box} void
set focus: {box} void
set read only: {box, bool} void
is read only: {box} bool
set enable: {box, bool} void
end
//[cf]
//[of]:sys box
//[of]:type
public struct sys box
widget: GtkWidget
key mask: dword
cursor: cursor
private visible : bool
private enabled : bool
accept drop files: bool
activated: bool
read only: bool
private input method: GtkIMContext
private right pressed : bool
end
//[cf]
//[c]
//[of]:signal functions
//[of]:connect (event, function)
public func connect (m: box, event: [] gchar, function: -> void)
return g_signal_connect(
widget (m),
event,
function:GCallback,
m)
end
//[cf]
//[of]:disconnect (handler)
public func disconnect (m: box, handler: gulong)
g_signal_handler_disconnect (widget (m), handler)
end
//[cf]
//[cf]
//[of]:event handling
//[of]:commit (input method, string, box)
//[c]Recieved an UTF-8 string
//[c]
func commit (im: GtkIMContext, s: string, m: box)
def bytes: [1] gsize
def p = from UTF8 (s, -1, bytes)
def n = bytes[0]
while n > 0:gsize
def c = p++[]
def ec : local char event
type (ec) = char event type
char code (ec) = c
status (ec) = 0
on char (m, ec)
n -= 1:gsize
end
end
//[cf]
//[of]:key press event (widget, event, box)
//[c]A key has been pressed
//[c]
public func key press event (w: GtkWidget, ev: GdkEventKey, m: box)
// Hack - GTK+ sends the event to the toplevel first
// this step force ignoring event by SWIFT
if parent (m) == nil
def handled = gtk_window_propagate_key_event (w : GtkWindow, ev)
if handled == FALSE
gtk_window_activate_key (w : GtkWindow, ev)
end
return TRUE
end
if gtk_widget_is_focus (w) == FALSE
return FALSE
end
def k = keyval (ev) : int
def e : local key event
type (e) = key down event type
status (e) = get key state (state (ev))
if k == GDK_ISO_Left_Tab
k = VK TAB
end
if k >= $a:int && k <= $z:int
key (e) = k - 32
else
key (e) = k
end
def processed = on key down (m, e)
def uc = gdk_keyval_to_unicode (k)
// some key have several codes
switch k
case VK LCONTROL, VK RCONTROL
k = VK CONTROL
case VK LSHIFT, VK RSHIFT
k = VK SHIFT
case VK LMENU, VK RMENU
k = VK MENU
else
k = 0
end
if k <> 0
key (e) = k
processed |= on key down (m, e)
end
if ~ processed
// Create the input method multicontext on demand in order
// to create useless objects
def im = input method (m)
if is nil (im)
im = gtk_im_multicontext_new
input method (m) = im
g_signal_connect (
im,
"commit",
^commit (GtkIMContext, string, box): GCallback,
m)
gtk_im_context_set_client_window(im, gtk_widget_get_window(w))
end
gtk_im_context_filter_keypress(im, ev)
end
return bool to gboolean (processed)
end
//[cf]
//[of]:key release event (widget, event, box)
//[c]A key has been released
//[c]
public func key release event (w: GtkWidget, ev: GdkEventKey, m: box)
// hack - gtk sends the event to the toplevel first
// this step force ignoring event
if gtk_widget_is_focus (w) == FALSE
return FALSE
end
def e : local key event
def k = keyval (ev) : int
type (e) = key up event type
status (e) = get key state (state (ev))
key (e) = k
def processed = on key up (m, e)
// some key have several codes
switch k
case VK LCONTROL, VK RCONTROL
k = VK CONTROL
case VK LSHIFT, VK RSHIFT
k = VK SHIFT
case VK LMENU, VK RMENU
k = VK MENU
else
k = 0
end
if k <> 0
key (e) = k
processed |= on key up (m, e)
end
return bool to gboolean (processed)
end
//[cf]
//[of]:focus in event (widget, event, box)
//[c]The control has gained the focus
//[c]
public func focus in event (w: GtkWidget, e: GdkEventFocus, m: box)
//[c]
//[c] The clipboards needs to be updated: update now.
//[c] "update targets" re-enters the message loop, that's why it can not be
//[c] invoked from anywhere. The destroy event could be handled at an
//[c] unexpected location, resulting operation on destroyed widgets.
//[c]
//[c] The "clipboard need update" is set when the window is reactivated
//[c] (see in frame.zc).
//[c]
if clipboard need update
update targets
clipboard need update = false
end
//[c]
//[c] GTK+ sometimes restore focus on an hidden control (notebook)
//[c] Check visibility first.
//[c]
if ~ is visible (m)
return FALSE
end
//[c]
return bool to gboolean (on focus (m))
end
//[cf]
//[of]:focus out event (widget, event, box)
//[c]The control has lost the focus
//[c]
public func focus out event (w: GtkWidget, e: GdkEventFocus, m: box)
return bool to gboolean (on blur (m))
end
//[cf]
//[of]:button press event (widget, event, box)
//[c]A button has been pressed
//[c]
public func button press event (
w: GtkWidget,
ev: GdkEventButton,
m: box)
def b = gdk_event_button_button (ev)
if b >= 1 && b < 4
def e: local mouse button event
button (e) = (
(b == 1) -> left mouse button,
(b == 3) -> right mouse button,
middle mouse button)
status (e) = get key state (state (ev))
x (position (e)) = max (0, gdk_event_button_get_x (ev))
y (position (e)) = max (0, gdk_event_button_get_y (ev))
if type (ev) == GDK_2BUTTON_PRESS
type (e) = mouse double click event type
return bool to gboolean (on mouse double click (m, e))
else
type (e) = mouse down event type
right pressed (m) = (button (e) == right mouse button)
return bool to gboolean (on mouse down (m, e))
end
end
return FALSE
end
//[cf]
//[of]:button release event (widget, event, box)
//[c]A button has been released
//[c]
public func button release event (
w: GtkWidget,
ev: GdkEventButton,
m: box)
def b = gdk_event_button_button (ev)
if b >= 1 && b < 4
def e: local mouse button event
type (e) = mouse up event type
button (e) = (
(b == 1) -> left mouse button,
(b == 3) -> right mouse button,
middle mouse button)
status (e) = get key state (state (ev))
x (position (e)) = max (0, gdk_event_button_get_x (ev))
y (position (e)) = max (0, gdk_event_button_get_y (ev))
def processed = on mouse up (m, e)
// Right click -> simulate a popup menu
if ~ processed && button (e) == right mouse button && right pressed (m)
right pressed (m) = false
processed = popup menu (m, position (e))
end
return bool to gboolean (processed)
end
return FALSE
end
//[cf]
//[of]:destroy (widget, box)
//[c]
private func destroy (widget: GtkWidget, m: box)
// the widget pointer is cleared
widget (m) = nil
return FALSE
end
//[cf]
//[of]:size allocate (widget, allocation, box)
private func size allocate (w: GtkWidget, a: GtkAllocation, m: box)
def r = client rect (m)
x (r) = 0
y (r) = 0
w (r) = width (a)
h (r) = height (a)
on size (m)
end
//[cf]
//[of]:drag data received (widget, ...)
//[c]
private func drag data received (
w: GtkWidget,
context: GdkDragContext,
x: gint,
y: gint,
selection data: GtkSelectionData,
info: guint,
time: guint,
m: box)
def uri : local uri
def e : local drop files event
def list = list (e)
initialize (list, 8)
def p = data (selection data) : string
repeat
def c = p []
if is nul (c)
break
end
// read line
def t := temp string buffer
repeat
c = p []
if is nul (c)
break
end
++ p
if c == \r
if p[] == \n
++p
end
break
end
if c == \n
break
end
t << c
end
// convert string to an uri
initialize (uri, as string (t))
release (t)
if is equal (scheme (uri), "file")
def u := convert uri to filename (uri)
def filename = new string (u)
add (list, filename)
release (u)
end
release (uri)
end
if size (list) > 0
on drop files (m, e)
end
// delete the list
each (list) ? s
delete (s)
end
release (list)
end
//[cf]
//[of]:popup menu (widget, win box)
//[c]
private func popup menu (widget: GtkWidget, m: box)
def pt: local point
x (pt) = 0
y (pt) = 0
return popup menu (m, pt)
end
//[cf]
//[cf]
//[of]:private
//[of]:globals
//[c]
//[c]The box being created.
//[c]Used during initialization of a window before the userdata is set
//[c]
private def box being created = nil: box
//[cf]
//[c]
//[of]:insert child (box)
//[c]
private func insert child (parent: box, child: box)
parent (child) = parent
next sibling (child) = nil
prev sibling (child) = last child (parent)
// update the head of the list
if is nil (first child (parent))
first child (parent) = child
end
// update successor
def last = last child (parent)
if not nil (last)
next sibling (last) = child
end
// update the tail of the list
last child (parent) = child
end
//[cf]
//[of]:remove child (box)
//[c]Removes a child box
//[c]
private func remove child (parent: box, child: box)
if first child (parent) == child
first child (parent) = next sibling (child)
end
if last child (parent) == child
last child (parent) = prev sibling (child)
end
if not nil (prev sibling (child))
next sibling (prev sibling (child)) = next sibling (child)
end
if not nil (next sibling (child))
prev sibling (next sibling (child)) = prev sibling (child)
end
next sibling (child) = nil
prev sibling (child) = nil
parent (child) = nil
end
//[cf]
//[cf]
//[c]
//[of]:activate
public func activate (m: box)
if ~ activated (m)
activate (class (m)) {m}
activated (m) = true
end
end
//[cf]
//[of]:actual set focus
//[c]
public func actual set focus (m: box)
if can get focus (m)
// if the control seems to accept focus, call the windows
// API to transfer actually the focus to the control
gtk_widget_grab_focus (widget (m))
else
// the control does not accept the focus, transfer the
// focus to the next valid control.
transfer focus (m, false)
end
end
//[cf]
//[of]:actual set enable (bool)
//[c]
public func actual set enable (m: box, en: bool)
// exit if unchanged
if enabled (m) == en
return
end
def sensitive = en -> TRUE, FALSE
gtk_widget_set_sensitive (widget (m), sensitive)
enabled (m) = en
end
//[cf]
//[of]:actual is read only
public func actual is read only (m: box)
return read only (m)
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -