The C64 OS Programmer's Guide is being written

This guide is being written and released and few chapters at a time. If a chapter seems to be empty, or if you click a chapter in the table of contents but it loads up Chapter 1, that's mostly likely because the chapter you've clicked doesn't exist yet.

Discussion of development topics are on-going about what to put in this guide. The discusssions are happening in the C64 OS Community Support Discord server, available to licensed C64 OS users.

C64 OS PROGRAMMER'S GUIDE

Class Reference: TKButton:TKCtrl:TKView:TKObj

Overview

TKButton is a concrete subclass of TKCtrl. It draws a single line button with text and optionally a icon on the left end, depending on how it's configured.

A TKButton object can be configured as a standard push button, a cycle button, a checkbox or a radio button. Push buttons and cycle buttons may optionally be configured as continuous, allowing the user to click and hold on the button and its action is triggered repeated until the mouse button is released.

There are several configurable options to customize a TKButton to fit the requirements of the user interface.

Subclassing notes

TKButton already has a fair number of configurable options and modes. It could be subclassed to add other options, but this is not usually required.

Class Definition

//os/tk/h/:tkbutton.h

Subclass Method Overrides

Init (init_)

During initialization, TKButton is anchored top, left with a height of 1. It defaults to a push button (bt_psh) with a title of "Button". It has a default left padding of 1. This puts a single space between the start of the button and the start of the button text. This can be adjusted later for tight contexts where the button text needs to fill the button.

Default and adjusted TKButton left padding.
Default and adjusted TKButton left padding

Left Mouse Down (musdown_)

Mouse down sets the cf_hilit flag on the cflags property so the button draws in a highlighted color.

The state of the COMMODORE key is also read from the mouse down event and affects a cycle direction flag. Without the COMMODORE key the cycle direction value is +1, with the COMMODORE key held down the cycle direction value is -1. This flag is only relevant if the button configured as a cycle button.

Left Mouse Up (musup_)

On mouse up the cf_hilit flag on the cflags property is cleared so the button draws in its normal state again.

Left Mouse Click (musclik_)

A click event has several different behaviors depending on how the button is configured.

If the cf_disab bit of the button's cflags property is set then a click does nothing. The superclass method is called and no other custom behaviors of TKButton occur.

If the button is a checkbox, bt_chk, the cf_state bit is toggled on the cflags property.

If the button is a radio button, bt_rad, the method setstate_ is called on this button. The setstate_ method is used because there is logic that affects the state of the other radio buttons in a circularly linked set.

A cycle button, bt_cyc, must have its value set to a single byte. In the current implementation cycle buttons are limited to an 8-bit unsigned range. The value is read and the cycle direction value which was determined during mouse down is added to the value. A range check is then performed. If value is greater than maxval it is replaced by minval. If value is less than minval it is replaced by maxval.

Lastly, the button's action is triggered. The state of a radio button or a checkbox being toggled, or the value of a cycle button being incremented or decremented, is independent of the button's action being fired.

For a cycle button, it is the responsibility of the action method to update the cycle button's title based on its new value.

For example, you may configure a TKButton as a cycle button with the intention of using it to show the months of the year. January may have a value of 0 and December a value of 11. The controlling code should have a string store for months of the year. When the button is instantiated it should be given a minval of 0 and a maxval of 11. It should then be assigned a current value that falls within that range.

To set the initial title of the button, call the settitle_ method. The initial value should be used to retrieve a string pointer from the string store and that pointer can be passed to the settitle_ method. Later, when the button is clicked, its value is automatically cycled and kept within the min/max range, but its title is not updated automatically. The action routine must call the settitle_ method on the sender, and use its current value to lookup the string pointer for its new title.

Draw (draw_)

The draw method of TKButton takes many state and configuration properties into consideration.

Radio buttons and checkboxes do not draw a bounding box. Therefore, they have the appearence of a radio or checkbox icon to the left of what appears to be a label. However, because that label is the title of the button object, clicking anywhere inside the bounds of the button triggers that button's behavior. This is why clicking a checkbox's label toggles its checked state.

A radio button or checkbox may be in a surrounding context that is reversed or not reversed.

TKButton as radio buttons and checkboxes in reversed and non-reversed contexts.
TKButton as radio buttons and checkboxes in reversed and non-reversed contexts

When a radio button or checkbox will be drawn in a reversed context, such as on a Utility panel as shown above, the cf_rvrs bit of the cflags should be set. The bcolor property must be set to match surrounding context.

All other button types have a bounding box which necessitates drawing in reverse. The button text and any icon are always drawn in the global background color. The foreground of the bounding box depends on the state of the button. When disabled it uses the disabled color from the system's color theme. When highlighted it uses the selected color from the color theme.

Push buttons and cycle buttons may also optionally be flagged as the default control by setting the cf_deflt bit on the cflags property. A button that is not disabled and not highlighted (i.e., the mouse button is not held down on it) use either the button color or the default button color from the system's color theme.

When a radio button or checkbox is drawn in the highlighted state, only the icon is drawn with the highlighted color.

Radio buttons are drawn with the radio button icon first, checkboxes with the checkbox icon, both have checked and unchecked versions depending on the cf_state bit of cflags. Cycle buttons draw the cycle icon first.

Left padding, defined by the lpad property, is drawn following any icon.

The title of a button is drawn immediately after the left padding, and thus always left aligned. The title text of the button goes to the end of the string and then the remainder of the button's width is padded with spaces. If the button's width is too narrow to show the full title text, the title is automatically clipped at the right end of the button. There is currently no option for fixed right padding. Therefore, clipped button title text always ends up flush with the right end of the button.

Button Methods

Method Description Offset
settitle_ Set title string pointer 79
setstate_ Set button's state 82

Set title string pointer (settitle_)

Input Description
RegPtr → String Pointer Null-terminated button title string
Output Description
- None

Sets the string pointer into the title property. Marks the button dirty.

This method must be called by the action routine of a cycle button in order to update the title on the button to match the new value.

Set the button's state (setstate_)

Input Description
A → 0 Uncheck the button
A → !0 Check the button
Output Description
- None

Changing the state of a button sets or unsets the cf_state bit on the cflags property. Any button so affected by this method is also marked as dirty.

If the button is a checkbox, bt_chk, this method affects this object only.

If the button is a radio button, bt_rad, this method affects this button object first. If the state of this button object becomes unchecked then no other buttons are affected. If the state of this button becomes checked, then all the other button objects in the circularly linked chain of related buttons is unchecked and marked dirty.

When creating TKButton objects of type bt_rad it is necessary to link the objects together that belong to a set. See the description of the bnext property below.


Object Definition

//os/tk/s/:tkbutton.s

Object Size: 62 (+3) bytes

Action Properties

Property Description Size Offset
btype Button type 1 54
title Button title 2 55
lpad Left padding 1 57
bnext Next button 2 58
minval Minimum value 1 60
maxval Maximum value 1 61

Button type (btype)

During initialization btype is set to bt_psh making the object a push button.

This property can be changed after initialization to select which type this button object should be.

#setobj8 this,btype,bt_cyc
Constant Value Notes
bt_rad 0 Radio button
bt_chk 1 Checkbox
bt_cyc 2 Cycle button
bt_mnu 3 Menu button (not implemented)
bt_psh 4 Push button

Button title (title)

This property holds the pointer to the button's title string. This property should only be set with the settitle_ method.

Left padding (lpad)

This property holds the fixed number of columns of padding between the icon, if there is an icon, and the start of the button's title. The default is 1.

#setobj8 this,lpad,0
#setobj8 this,lpad,2

Next button (bnext)

Radio buttons affect each other. They must therefore by linked together in a group. This property is the mechanism of grouping them together. By default bnext is set to null, indicating that it is not part of a group of buttons.

The bnext property of one radio button object must be pointed to the next radio button object in the set. The last radio button in the set must have its bnext property pointed back to the first in the set, forming a circular, singly-linked list.

;Link 3 Radio Buttons

linkrad .macro

	#storeget views,\1
	#stxy this

	ldy #bnext
	lda views+(\2*2)+0
	sta (this),y
	iny
	lda views+(\2*2)+1
	sta (this),y

.endm


;rad0.bnext = rad1
#linkrad 0,1

;rad1.bnext = rad2
#linkrad 1,2

;rad2.bnext = rad0 (close the loop)
#linkrad 2,0

This linking procedure benefits from a macro, but you'll need to customize the macro for the object pointer store you're using.

Minimum and Maximum value (minval and maxval)

Only cycle buttons make use of a minimum value. It's used to help automate the most common case of cycling through a numeric range. If cycling forward would exceed the maxval the value is set to minval instead. If cycling in reverse would fall below minval the value is set to maxval instead.

If value is manually set to something outside the min/max range, it will be moved back to within the min/max range the first time the user clicks it. If minval is set larger than maxval the behavior is undefined.

The minval and maxval are 8-bit unsigned integers. Therefore, cycle buttons only support cycling from 0 to 255.

#setobj8 this,minval,5
#setobj8 this,maxval,12

Relationships

Inherits from: TKCtrl

Parent Section: Class Reference

Next Section: Subclassing


Next Chapter: Writing an Application

Table of Contents



This document is subject to revision updates.

Last modified: Oct 11, 2024