Skip to content

Instantly share code, notes, and snippets.

@BlakeRain
Created January 14, 2021 20:58
Show Gist options
  • Save BlakeRain/f62732c37dcb3a4950134a9b37d4913b to your computer and use it in GitHub Desktop.
Save BlakeRain/f62732c37dcb3a4950134a9b37d4913b to your computer and use it in GitHub Desktop.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
class ControlPanel(Gtk.Box):
def __init__(self):
super().__init__(orientation=Gtk.Orientation.VERTICAL, spacing=5)
# Place the control panel in the top right
self.set_halign(Gtk.Align.END)
self.set_valign(Gtk.Align.START)
# Add the .control-panel CSS class to this widget
context = self.get_style_context()
context.add_class("control-panel")
def add_group(self, group):
self.pack_start(group, False, False, 0)
class ControlPanelGroup(Gtk.Expander):
def __init__(self, title: str):
Gtk.Expander.__init__(self, label=title)
self._inner = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
# Set the size request to 200 pixels wide
self.set_size_request(200, -1)
# Add a bit of margin after the header
self._inner.set_margin_top(5)
self.add(self._inner)
def add_row(self, widget):
self._inner.pack_start(widget, False, False, 0)
class MyControlPanel(ControlPanel):
def __init__(self):
super().__init__()
self._first_panel = ControlPanelGroup("Some Buttons")
self._first_panel.add_row(Gtk.Button(label="Button 1"))
self._first_panel.add_row(Gtk.Button(label="Button 2"))
self.add_group(self._first_panel)
self._second_panel = ControlPanelGroup("Extra Settings")
self._second_panel.add_row(Gtk.Button(label="Button 3"))
self._second_panel.add_row(Gtk.Button(label="Button 4"))
self._second_panel.add_row(
Gtk.CheckButton.new_with_label("First checkbox"))
self._second_panel.add_row(
Gtk.CheckButton.new_with_label("Second checkbox"))
combo = Gtk.ComboBoxText()
combo.append("first", "First Choice")
combo.append("second", "Second Choice")
combo.append("third", "Third Choice")
combo.append("forth", "This one is quite long")
combo.set_active_id("first")
self._second_panel.add_row(combo)
self.add_group(self._second_panel)
class MapEditor(Gtk.DrawingArea):
def __init__(self):
super().__init__()
self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK |
Gdk.EventMask.BUTTON_RELEASE_MASK |
Gdk.EventMask.POINTER_MOTION_MASK)
self._camera_x = 0 # The X coordinate of the camera
self._camera_y = 0 # The Y coordinate of the camera
self._mouse_x = 0 # The X coordinate of the pointer
self._mouse_y = 0 # The Y coordinate of the pointer
self._button = None # The currently held mouse button
# Connect to the draw and mouse events
self.connect("draw", self.on_draw)
self.connect("button-press-event", self.on_button_press_event)
self.connect("button-release-event", self.on_button_release_event)
self.connect("motion-notify-event", self.on_motion_notify_event)
def on_button_press_event(self, widget, event):
self._mouse_x = event.x
self._mouse_y = event.y
self._button = event.button
def on_button_release_event(self, widget, event):
self._mouse_x = 0
self._mouse_y = 0
self._button = None
def on_motion_notify_event(self, widget, event):
if self._button == Gdk.BUTTON_SECONDARY:
self._camera_x += event.x - self._mouse_x
self._camera_y += event.y - self._mouse_y
self._mouse_x = event.x
self._mouse_y = event.y
self.queue_draw()
def on_draw(self, widget, context):
# Get the width and height of the widget
width = self.get_allocated_width()
height = self.get_allocated_height()
# Render a rectangle for the background of the editor
context.set_source_rgb(0.11, 0.11, 0.11)
context.rectangle(0, 0, width, height)
context.fill()
# Render our grids
context.set_line_width(1)
for color, step in [(0.2, 10), (0.3, 100)]:
context.set_source_rgb(color, color, color)
y = int(self._camera_y % step) + 0.5
while y < height:
context.move_to(0, y)
context.line_to(width, y)
y += step
x = int(self._camera_x % step) + 0.5
while x < width:
context.move_to(x, 0)
context.line_to(x, height)
x += step
context.stroke()
class MainWindow(Gtk.Window):
def __init__(self):
super().__init__()
self.set_title("Collapsible Controls Overlay Demo")
# Set the default window size to 800x800
self.set_default_size(800, 800)
# When our window is destroyed, exit the main event loop
self.connect("destroy", Gtk.main_quit)
# Create our map editor and control panel instances
self._editor = MapEditor()
self._controls = MyControlPanel()
# Create the overlay widget
self._overlay = Gtk.Overlay()
# Add our editor and control panel as overlays
self._overlay.add_overlay(self._editor)
self._overlay.add_overlay(self._controls)
# Add the overlay as the immediate child of the window
self.add(self._overlay)
def install_css():
screen = Gdk.Screen.get_default()
provider = Gtk.CssProvider()
provider.load_from_data(b"""
.control-panel {
background-color: @bg_color;
padding: 4px;
border-bottom-left-radius: 4px;
}
""")
Gtk.StyleContext.add_provider_for_screen(screen, provider, 600)
install_css()
window = MainWindow()
window.show_all()
Gtk.main()
@domdog
Copy link

domdog commented Sep 20, 2022

This and your article are wonderful.
Thank You.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment