Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add notebook #118

Draft
wants to merge 24 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fa0ce71
Add first stap at wrapping notebook
PhilippMDoerner Oct 13, 2023
286b7bb
Move gtk.nim into bindings dir
PhilippMDoerner Oct 14, 2023
95d7138
Refactor adwaita bindings into a binding module
PhilippMDoerner Oct 14, 2023
b260c07
Re export bound enums
PhilippMDoerner Oct 14, 2023
451989f
Merge branch 'main' into refactor-bindings
PhilippMDoerner Oct 15, 2023
6dda78a
Add SearchEntry widget
PhilippMDoerner Oct 17, 2023
7a0ce6c
Add PasswordEntry widget
PhilippMDoerner Oct 17, 2023
161600d
Add ActionBar widget
PhilippMDoerner Oct 17, 2023
c0598c6
Add examples to .gitignore
can-lehmann Oct 17, 2023
4368f12
Update docs
can-lehmann Oct 17, 2023
36509eb
Merge branch 'main' into refactor-bindings
PhilippMDoerner Oct 17, 2023
b9a8f14
Merge branch 'refactor-bindings' into add-notebook
PhilippMDoerner Oct 19, 2023
ca6194e
Add first draft of notebook widget
PhilippMDoerner Oct 19, 2023
1335e54
Get rid of GTK Errors
PhilippMDoerner Oct 19, 2023
5362b8e
Refine example
PhilippMDoerner Oct 19, 2023
c2230cf
Add currentPage property
PhilippMDoerner Oct 19, 2023
ec7cad5
Add first signals
PhilippMDoerner Oct 19, 2023
26c18dc
Fix notebook not updating attributes of tabs
PhilippMDoerner Oct 20, 2023
81e78e6
Hide/Disable unsupported features
PhilippMDoerner Oct 20, 2023
6b4e991
Fix notebook not being able to trigger events from label widget
PhilippMDoerner Oct 20, 2023
bb098e9
Enable setting a Widget for notebook
PhilippMDoerner Oct 20, 2023
d2dde8f
Enable setting a menu widget for notebook
PhilippMDoerner Oct 20, 2023
da01849
Merge branch 'main' into add-notebook
PhilippMDoerner Oct 21, 2023
01b6357
Merge branch 'main' of github.com:can-lehmann/owlkettle into add-note…
PhilippMDoerner Nov 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions examples/widgets/notebook.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# MIT License
#
# Copyright (c) 2022 Can Joshua Lehmann
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import std/[sequtils, strformat, sugar]
import owlkettle, owlkettle/[dataentries, playground, adw]

type Page = tuple[tabLabel: string, menuLabel: string, reorderable: bool]

viewable App:
enablePopup: bool = true
groupName: string
scrollable: bool = true
showBorder: bool = true
showTabs: bool = true
tabPosition: TabPositionType = TabTop
currentPage: int = 0
sensitive: bool = true
tooltip: string = ""
sizeRequest: tuple[x, y: int] = (-1, -1)

pages: seq[Page] = (1..3).mapIt(
(fmt"Tab {it}", fmt"Tab {it}" , true)
)

proc tabLabelWidget(app: AppState, index: int): Widget =
let text = app.pages[index].tabLabel
result = gui:
Box(orient = OrientX):
Label(text = text)
Button() {.expand: false.}:
style = [ButtonFlat]
icon = "window-close"

proc clicked() =
app.pages.delete(index)

proc tabMenuWidget(app: AppState, index: int): Widget =
let text = app.pages[index].menuLabel

result = gui:
Box(orient = OrientX):
Label(text = text)
Icon() {.expand: false.}:
name = "window-close"


method view(app: AppState): Widget =
let labelWidgets = collect(newSeq):
for num in app.pages.low..app.pages.high:
tabLabelWidget(app, num)

let menuWidgets = collect(newSeq):
for num in app.pages.low..app.pages.high:
tabMenuWidget(app, num)

result = gui:
Window():
title = "Notebook Example"
defaultSize = (600, 300)
HeaderBar() {.addTitlebar.}:
insert(app.toAutoFormMenu(sizeRequest = (800, 700))) {.addRight.}

Notebook():
enablePopup = app.enablePopup
groupName = app.groupName
scrollable = app.scrollable
showBorder = app.showBorder
showTabs = app.showTabs
tabPosition = app.tabPosition
currentPage = app.currentPage
sensitive = app.sensitive
tooltip = app.tooltip
sizeRequest = app.sizeRequest

proc switchPage(newPageIndex: int) =
echo "New Page Index: ", newPageIndex

proc pageAdded(newPageIndex: int) =
## TODO: Currently not working, maybe page is not removed via the right proc?
echo "Page ", newPageIndex, " Added"

proc pageRemoved(removedPageIndex: int) =
## TODO: Currently not working, maybe page is not removed via the right proc?
echo "Page ", removedPageIndex, " Removed"

proc pageReordered(newPageIndex: int) =
echo "Page moved to new index ", newPageIndex

for index, page in app.pages:
Box(orient = OrientY) {.tabLabelWidget: labelWidgets[index], menuLabelWidget: menuWidgets[index], reorderable: page.reorderable.}:
Label(text = fmt"Some Content of Page {index+1}") {.expand: false.}
Label(text = fmt" Reorderable: {page.reorderable}") {.expand: false.}

adw.brew(gui(App()))
36 changes: 36 additions & 0 deletions owlkettle/bindings/gtk.nim
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,14 @@ type
k, l, m: cint
n: pointer

GtkDirectionType* = enum
GTK_DIR_TAB_FORWARD
GTK_DIR_TAB_BACKWARD
GTK_DIR_UP
GTK_DIR_DOWN
GTK_DIR_LEFT
GTK_DIR_RIGHT

GtkDrawingAreaDrawFunc* = proc(area: GtkWidget, ctx: pointer, width, height: cint, data: pointer) {.cdecl.}

type
Expand Down Expand Up @@ -829,6 +837,34 @@ proc gtk_drawing_area_set_draw_func*(widget: GtkWidget,
# Gtk.Native
proc gtk_native_get_surface_transform*(native: GtkWidget, x, y: ptr cdouble)

# Gtk.Notebook
proc gtk_notebook_new*(): GtkWidget
proc gtk_notebook_append_page*(widget: GtkWidget, child: GtkWidget, tab_label: GtkWidget): cint
proc gtk_notebook_append_page_menu*(widget: GtkWidget, child: GtkWidget, tab_label: GtkWidget, menu_label: GtkWidget): cint
proc gtk_notebook_detach_tab*(widget: GtkWidget, child: GtkWidget)
proc gtk_notebook_insert_page*(widget: GtkWidget, child: GtkWidget, tab_label: GtkWidget, position: cint): cint
proc gtk_notebook_insert_page_menu*(widget: GtkWidget, child: GtkWidget, tab_label: GtkWidget, menu_label: GtkWidget, position: cint): cint
proc gtk_notebook_next_page*(widget: GtkWidget)
proc gtk_notebook_popup_enable*(widget: GtkWidget)
proc gtk_notebook_popup_disable*(widget: GtkWidget)
proc gtk_notebook_prepend_page*(widget: GtkWidget, child: GtkWidget, tab_label: GtkWidget): cint
proc gtk_notebook_prev_page*(widget: GtkWidget)
proc gtk_notebook_remove_page*(widget: GtkWidget, page_num: cint)
proc gtk_notebook_set_action_widget*(notebook: GtkWidget, widget: GtkWidget, pack_type: GtkPackType)
proc gtk_notebook_set_current_page*(widget: GtkWidget, page_num: cint)
proc gtk_notebook_set_group_name*(widget: GtkWidget, group_name: cstring)
proc gtk_notebook_set_menu_label*(widget: GtkWidget, child: GtkWidget, menu_label: GtkWidget)
proc gtk_notebook_set_menu_label_text*(widget: GtkWidget, child: GtkWidget, menu_text: cstring)
proc gtk_notebook_set_scrollable*(widget: GtkWidget, scrollable: cbool)
proc gtk_notebook_set_show_border*(widget: GtkWidget, show_border: cbool)
proc gtk_notebook_set_show_tabs*(widget: GtkWidget, show_tabs: cbool)
proc gtk_notebook_set_tab_detachable*(widget: GtkWidget, child: GtkWidget, detachable: cbool)
proc gtk_notebook_set_tab_label_text*(widget: GtkWidget, child: GtkWidget, tab_text: cstring)
proc gtk_notebook_set_tab_pos*(widget: GtkWidget, pos: GtkPositionType)
proc gtk_notebook_set_tab_reorderable*(widget: GtkWidget, child: GtkWidget, reorderable: cbool)
proc gtk_notebook_get_group_name*(widget: GtkWidget): cstring
proc gtk_notebook_get_menu_label*(widget, child: GtkWidget): GtkWidget
proc gtk_notebook_get_tab_label*(widget, child: GtkWidget): GtkWidget
# Gtk.EventController
proc gtk_event_controller_get_widget*(cont: GtkEventController): GtkWidget

Expand Down
32 changes: 32 additions & 0 deletions owlkettle/playground.nim
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,38 @@ proc toFormField(state: Viewable, field: ptr ScaleMark, fieldName: string): Widg
proc select(enumIndex: int) =
field[].position = enumIndex.ScalePosition

proc toFormField(state: auto, fieldName: static string, index: int, typ: typedesc[tuple[tabLabel: string, menuLabel: string, reorderable: bool]]): Widget =
## Provides a form to display a single entry of type `tuple[name: string, title: string, text: string]` in a list of entries.
let tup = state.getField(fieldName)[index]
return gui:
ActionRow:
title = "(tab, menu, reorderable, detachable)"
Entry() {.addSuffix.}:
text = state.getField(fieldName)[index].tabLabel
proc changed(text: string) =
state.getField(fieldName)[index].tabLabel = text

Entry() {.addSuffix.}:
text = state.getField(fieldName)[index].menuLabel
proc changed(text: string) =
state.getField(fieldName)[index].menuLabel = text

Switch() {.addSuffix.}:
state = state.getField(fieldName)[index].reorderable
proc changed(newVal: bool) =
state.getField(fieldName)[index].reorderable = newVal

Button {.addSuffix.}:
icon = "user-trash-symbolic"
proc clicked() =
state.getField(fieldName).delete(index)

proc default(t: typedesc[tuple[tabLabel: string, menuLabel: string, reorderable: bool]]): tuple[tabLabel: string, menuLabel: string, reorderable: bool] =
("new Tab", "new TabMenu", false)

proc toFormField[T](state: auto, fieldName: static string, typ: typedesc[seq[T]]): Widget =
## Provides a form field for any field on `state` with a seq type.
## Displays a dummy widget if there is no `toListFormField` implementation for type T.
proc addDeleteButton(formField: Widget, value: ptr seq[auto], index: int) =
let button = gui:
Button():
Expand Down
Loading