Created
January 14, 2021 20:58
-
-
Save BlakeRain/f62732c37dcb3a4950134a9b37d4913b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This and your article are wonderful.
Thank You.